[RTL] Add support for shaping in background thread.

This commit is contained in:
bruvzg 2022-05-18 10:17:55 +03:00
parent 5631b59e21
commit cfcdfc38e2
No known key found for this signature in database
GPG key ID: 7960FCF39844EC38
9 changed files with 779 additions and 338 deletions

View file

@ -60,6 +60,7 @@
<argument index="0" name="character" type="int" />
<description>
Returns the line number of the character position provided.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_character_paragraph">
@ -67,24 +68,28 @@
<argument index="0" name="character" type="int" />
<description>
Returns the paragraph number of the character position provided.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_content_height" qualifiers="const">
<return type="int" />
<description>
Returns the height of the content.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_content_width" qualifiers="const">
<return type="int" />
<description>
Returns the width of the content.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_line_count" qualifiers="const">
<return type="int" />
<description>
Returns the total number of lines in the text. Wrapped text is counted as multiple lines.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_line_offset">
@ -92,6 +97,7 @@
<argument index="0" name="line" type="int" />
<description>
Returns the vertical offset of the line found at the provided index.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_menu" qualifiers="const">
@ -112,6 +118,7 @@
<argument index="0" name="paragraph" type="int" />
<description>
Returns the vertical offset of the paragraph found at the provided index.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_parsed_text" qualifiers="const">
@ -155,12 +162,14 @@
<return type="int" />
<description>
Returns the number of visible lines.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="get_visible_paragraph_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of visible paragraphs. A paragraph is considered visible if at least one of its lines is visible.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
</description>
</method>
<method name="install_effect">
@ -176,6 +185,12 @@
Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided).
</description>
</method>
<method name="is_ready" qualifiers="const">
<return type="bool" />
<description>
If [member threaded] is enabled, returns [code]true[/code] if the background thread has finished text processing, otherwise always return [code]true[/code].
</description>
</method>
<method name="newline">
<return type="void" />
<description>
@ -476,6 +491,10 @@
The range of characters to display, as a [float] between 0.0 and 1.0. When assigned an out of range value, it's the same as assigning 1.0.
[b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count].
</member>
<member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000">
The delay after which the loading progress bar is displayed, in milliseconds. Set to [code]-1[/code] to disable progress bar entirely.
[b]Note:[/b] Progress bar is dislayed only if [member threaded] is enabled.
</member>
<member name="scroll_active" type="bool" setter="set_scroll_active" getter="is_scroll_active" default="true">
If [code]true[/code], the scrollbar is visible. Setting this to [code]false[/code] does not block scrolling completely. See [method scroll_to_line].
</member>
@ -504,6 +523,9 @@
<member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0">
Base text writing direction.
</member>
<member name="threaded" type="bool" setter="set_threaded" getter="is_threaded" default="false">
If [code]true[/code], text processing is done in a background thread.
</member>
<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed.
[b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count].
@ -513,6 +535,11 @@
</member>
</members>
<signals>
<signal name="finished">
<description>
Triggered when the document is fully loaded.
</description>
</signal>
<signal name="meta_clicked">
<argument index="0" name="meta" type="Variant" />
<description>

View file

@ -196,6 +196,7 @@ EditorAbout::EditorAbout() {
// License
_license_text = memnew(RichTextLabel);
_license_text->set_threaded(true);
_license_text->set_name(TTR("License"));
_license_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
_license_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@ -272,6 +273,7 @@ EditorAbout::EditorAbout() {
tpl_hbc->add_child(_tpl_tree);
_tpl_text = memnew(RichTextLabel);
_tpl_text->set_threaded(true);
_tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
_tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tpl_hbc->add_child(_tpl_text);

View file

@ -235,7 +235,7 @@ String EditorHelp::_fix_constant(const String &p_constant) const {
}
void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview) {
method_line[p_method.name] = class_desc->get_line_count() - 2; //gets overridden if description
method_line[p_method.name] = class_desc->get_paragraph_count() - 2; //gets overridden if description
const bool is_vararg = p_method.qualifiers.contains("vararg");
@ -593,8 +593,8 @@ void EditorHelp::_update_doc() {
// Class description
if (!cd.description.is_empty()) {
section_line.push_back(Pair<String, int>(TTR("Description"), class_desc->get_line_count() - 2));
description_line = class_desc->get_line_count() - 2;
section_line.push_back(Pair<String, int>(TTR("Description"), class_desc->get_paragraph_count() - 2));
description_line = class_desc->get_paragraph_count() - 2;
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Description"));
@ -664,7 +664,7 @@ void EditorHelp::_update_doc() {
}
if (has_properties) {
section_line.push_back(Pair<String, int>(TTR("Properties"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Properties"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Properties"));
@ -682,7 +682,7 @@ void EditorHelp::_update_doc() {
if (cd.properties[i].name.begins_with("_") && cd.properties[i].description.is_empty()) {
continue;
}
property_line[cd.properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
property_line[cd.properties[i].name] = class_desc->get_paragraph_count() - 2; //gets overridden if description
// Property type.
class_desc->push_cell();
@ -828,7 +828,7 @@ void EditorHelp::_update_doc() {
cd.constructors.sort();
}
section_line.push_back(Pair<String, int>(TTR("Constructors"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Constructors"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Constructors"));
@ -839,7 +839,7 @@ void EditorHelp::_update_doc() {
if (sort_methods) {
methods.sort();
}
section_line.push_back(Pair<String, int>(TTR("Methods"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Methods"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Methods"));
@ -851,7 +851,7 @@ void EditorHelp::_update_doc() {
cd.operators.sort();
}
section_line.push_back(Pair<String, int>(TTR("Operators"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Operators"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Operators"));
@ -860,7 +860,7 @@ void EditorHelp::_update_doc() {
// Theme properties
if (!cd.theme_properties.is_empty()) {
section_line.push_back(Pair<String, int>(TTR("Theme Properties"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Theme Properties"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Theme Properties"));
@ -882,7 +882,7 @@ void EditorHelp::_update_doc() {
data_type_names["style"] = TTR("Styles");
for (int i = 0; i < cd.theme_properties.size(); i++) {
theme_property_line[cd.theme_properties[i].name] = class_desc->get_line_count() - 2; // Gets overridden if description.
theme_property_line[cd.theme_properties[i].name] = class_desc->get_paragraph_count() - 2; // Gets overridden if description.
if (theme_data_type != cd.theme_properties[i].data_type) {
theme_data_type = cd.theme_properties[i].data_type;
@ -954,7 +954,7 @@ void EditorHelp::_update_doc() {
cd.signals.sort();
}
section_line.push_back(Pair<String, int>(TTR("Signals"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Signals"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Signals"));
@ -967,7 +967,7 @@ void EditorHelp::_update_doc() {
class_desc->push_indent(1);
for (int i = 0; i < cd.signals.size(); i++) {
signal_line[cd.signals[i].name] = class_desc->get_line_count() - 2; // Gets overridden if description.
signal_line[cd.signals[i].name] = class_desc->get_paragraph_count() - 2; // Gets overridden if description.
class_desc->push_font(doc_code_font); // monofont
class_desc->push_color(headline_color);
@ -1040,7 +1040,7 @@ void EditorHelp::_update_doc() {
// Enums
if (enums.size()) {
section_line.push_back(Pair<String, int>(TTR("Enumerations"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Enumerations"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Enumerations"));
@ -1051,7 +1051,7 @@ void EditorHelp::_update_doc() {
class_desc->add_newline();
for (KeyValue<String, Vector<DocData::ConstantDoc>> &E : enums) {
enum_line[E.key] = class_desc->get_line_count() - 2;
enum_line[E.key] = class_desc->get_paragraph_count() - 2;
class_desc->push_font(doc_code_font);
class_desc->push_color(title_color);
@ -1098,7 +1098,7 @@ void EditorHelp::_update_doc() {
}
// Add the enum constant line to the constant_line map so we can locate it as a constant.
constant_line[enum_list[i].name] = class_desc->get_line_count() - 2;
constant_line[enum_list[i].name] = class_desc->get_paragraph_count() - 2;
class_desc->push_font(doc_code_font);
class_desc->push_color(headline_color);
@ -1144,7 +1144,7 @@ void EditorHelp::_update_doc() {
// Constants
if (constants.size()) {
section_line.push_back(Pair<String, int>(TTR("Constants"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Constants"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Constants"));
@ -1155,7 +1155,7 @@ void EditorHelp::_update_doc() {
class_desc->add_newline();
for (int i = 0; i < constants.size(); i++) {
constant_line[constants[i].name] = class_desc->get_line_count() - 2;
constant_line[constants[i].name] = class_desc->get_paragraph_count() - 2;
class_desc->push_font(doc_code_font);
if (constants[i].value.begins_with("Color(") && constants[i].value.ends_with(")")) {
@ -1205,7 +1205,7 @@ void EditorHelp::_update_doc() {
// Property descriptions
if (property_descr) {
section_line.push_back(Pair<String, int>(TTR("Property Descriptions"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Property Descriptions"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Property Descriptions"));
@ -1220,7 +1220,7 @@ void EditorHelp::_update_doc() {
continue;
}
property_line[cd.properties[i].name] = class_desc->get_line_count() - 2;
property_line[cd.properties[i].name] = class_desc->get_paragraph_count() - 2;
class_desc->push_table(2);
class_desc->set_table_column_expand(1, true);
@ -1371,7 +1371,7 @@ void EditorHelp::_update_doc() {
// Constructor descriptions
if (constructor_descriptions) {
section_line.push_back(Pair<String, int>(TTR("Constructor Descriptions"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Constructor Descriptions"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Constructor Descriptions"));
@ -1380,7 +1380,7 @@ void EditorHelp::_update_doc() {
// Method descriptions
if (method_descriptions) {
section_line.push_back(Pair<String, int>(TTR("Method Descriptions"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Method Descriptions"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Method Descriptions"));
@ -1389,7 +1389,7 @@ void EditorHelp::_update_doc() {
// Operator descriptions
if (operator_descriptions) {
section_line.push_back(Pair<String, int>(TTR("Operator Descriptions"), class_desc->get_line_count() - 2));
section_line.push_back(Pair<String, int>(TTR("Operator Descriptions"), class_desc->get_paragraph_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Operator Descriptions"));
@ -1868,6 +1868,7 @@ EditorHelp::EditorHelp() {
class_desc = memnew(RichTextLabel);
add_child(class_desc);
class_desc->set_threaded(true);
class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));

View file

@ -1691,6 +1691,8 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_
}
RID TextServerAdvanced::create_font() {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = memnew(FontDataAdvanced);
return font_owner.make_rid(fd);
@ -3359,6 +3361,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
sd->hb_buffer = hb_buffer_create();
sd->direction = p_direction;
@ -3748,6 +3751,8 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
}
RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
_THREAD_SAFE_METHOD_
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());

View file

@ -853,6 +853,8 @@ _FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontDataFallback *p_fo
}
RID TextServerFallback::create_font() {
_THREAD_SAFE_METHOD_
FontDataFallback *fd = memnew(FontDataFallback);
return font_owner.make_rid(fd);
@ -2429,6 +2431,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
sd->direction = p_direction;
sd->orientation = p_orientation;
@ -2807,6 +2810,8 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
}
RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
_THREAD_SAFE_METHOD_
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());

File diff suppressed because it is too large Load diff

View file

@ -141,10 +141,10 @@ private:
struct ItemFrame : public Item {
bool cell = false;
Vector<Line> lines;
int first_invalid_line = 0;
int first_invalid_font_line = 0;
int first_resized_line = 0;
LocalVector<Line> lines;
std::atomic<int> first_invalid_line;
std::atomic<int> first_invalid_font_line;
std::atomic<int> first_resized_line;
ItemFrame *parent_frame = nullptr;
@ -155,7 +155,12 @@ private:
Size2 max_size_over = Size2(-1, -1);
Rect2 padding;
ItemFrame() { type = ITEM_FRAME; }
ItemFrame() {
type = ITEM_FRAME;
first_invalid_line.store(0);
first_invalid_font_line.store(0);
first_resized_line.store(0);
}
};
struct ItemText : public Item {
@ -263,8 +268,8 @@ private:
int width = 0;
};
Vector<Column> columns;
Vector<float> rows;
LocalVector<Column> columns;
LocalVector<float> rows;
int total_width = 0;
int total_height = 0;
@ -363,6 +368,16 @@ private:
Item *current = nullptr;
ItemFrame *current_frame = nullptr;
Thread thread;
Mutex data_mutex;
bool threaded = false;
std::atomic<bool> stop_thread;
std::atomic<bool> updating;
std::atomic<double> loaded;
uint64_t loading_started = 0;
int progress_delay = 1000;
VScrollBar *vscroll = nullptr;
AutowrapMode autowrap_mode = AUTOWRAP_WORD_SMART;
@ -392,7 +407,11 @@ private:
Array custom_effects;
void _invalidate_current_line(ItemFrame *p_frame);
void _validate_line_caches(ItemFrame *p_frame);
static void _thread_function(void *self);
void _stop_thread();
bool _validate_line_caches();
void _process_line_caches();
void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false);
void _remove_item(Item *p_item, const int p_line, const int p_subitem_line);
@ -446,8 +465,9 @@ private:
bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search);
bool _search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search);
void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
float _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h, int *r_char_offset);
float _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h);
void _update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size);
int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs);
float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false);
@ -480,9 +500,9 @@ private:
bool _find_layout_subitem(Item *from, Item *to);
void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack);
void _update_scroll();
void _update_fx(ItemFrame *p_frame, double p_delta_time);
void _scroll_changed(double);
int _find_first_line(int p_from, int p_to, int p_vofs) const;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual String get_tooltip(const Point2 &p_pos) const override;
@ -611,6 +631,14 @@ public:
bool is_deselect_on_focus_loss_enabled() const;
void deselect();
bool is_ready() const;
void set_threaded(bool p_threaded);
bool is_threaded() const;
void set_progress_bar_delay(int p_delay_ms);
int get_progress_bar_delay() const;
// Context menu.
PopupMenu *get_menu() const;
bool is_menu_visible() const;

View file

@ -139,7 +139,7 @@ void TextParagraph::_bind_methods() {
void TextParagraph::_shape_lines() {
if (lines_dirty) {
for (int i = 0; i < lines_rid.size(); i++) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
@ -218,14 +218,14 @@ void TextParagraph::_shape_lines() {
// Fill after min_size calculation.
if (autowrap_enabled) {
int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
bool lines_hidden = visible_lines > 0 && visible_lines < (int)lines_rid.size();
if (lines_hidden) {
overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
}
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
for (int i = 0; i < lines_rid.size(); i++) {
if (i < visible_lines - 1 || lines_rid.size() == 1) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
if (i < visible_lines - 1 || (int)lines_rid.size() == 1) {
TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
} else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
@ -238,7 +238,7 @@ void TextParagraph::_shape_lines() {
} else {
// Autowrap disabled.
for (int i = 0; i < lines_rid.size(); i++) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
@ -258,8 +258,10 @@ RID TextParagraph::get_rid() const {
}
RID TextParagraph::get_line_rid(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), RID());
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), RID());
return lines_rid[p_line];
}
@ -268,9 +270,11 @@ RID TextParagraph::get_dropcap_rid() const {
}
void TextParagraph::clear() {
_THREAD_SAFE_METHOD_
spacing_top = 0;
spacing_bottom = 0;
for (int i = 0; i < lines_rid.size(); i++) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
@ -279,57 +283,79 @@ void TextParagraph::clear() {
}
void TextParagraph::set_preserve_invalid(bool p_enabled) {
_THREAD_SAFE_METHOD_
TS->shaped_text_set_preserve_invalid(rid, p_enabled);
TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled);
lines_dirty = true;
}
bool TextParagraph::get_preserve_invalid() const {
_THREAD_SAFE_METHOD_
return TS->shaped_text_get_preserve_invalid(rid);
}
void TextParagraph::set_preserve_control(bool p_enabled) {
_THREAD_SAFE_METHOD_
TS->shaped_text_set_preserve_control(rid, p_enabled);
TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled);
lines_dirty = true;
}
bool TextParagraph::get_preserve_control() const {
_THREAD_SAFE_METHOD_
return TS->shaped_text_get_preserve_control(rid);
}
void TextParagraph::set_direction(TextServer::Direction p_direction) {
_THREAD_SAFE_METHOD_
TS->shaped_text_set_direction(rid, p_direction);
TS->shaped_text_set_direction(dropcap_rid, p_direction);
lines_dirty = true;
}
TextServer::Direction TextParagraph::get_direction() const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
return TS->shaped_text_get_direction(rid);
}
void TextParagraph::set_custom_punctuation(const String &p_punct) {
_THREAD_SAFE_METHOD_
TS->shaped_text_set_custom_punctuation(rid, p_punct);
lines_dirty = true;
}
String TextParagraph::get_custom_punctuation() const {
_THREAD_SAFE_METHOD_
return TS->shaped_text_get_custom_punctuation(rid);
}
void TextParagraph::set_orientation(TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
TS->shaped_text_set_orientation(rid, p_orientation);
TS->shaped_text_set_orientation(dropcap_rid, p_orientation);
lines_dirty = true;
}
TextServer::Orientation TextParagraph::get_orientation() const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
return TS->shaped_text_get_orientation(rid);
}
bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(p_fonts.is_null(), false);
TS->shaped_text_clear(dropcap_rid);
dropcap_margins = p_dropcap_margins;
@ -339,12 +365,16 @@ bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts,
}
void TextParagraph::clear_dropcap() {
_THREAD_SAFE_METHOD_
dropcap_margins = Rect2();
TS->shaped_text_clear(dropcap_rid);
lines_dirty = true;
}
bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(p_fonts.is_null(), false);
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
@ -362,23 +392,31 @@ int TextParagraph::get_spacing_bottom() const {
}
void TextParagraph::set_bidi_override(const Array &p_override) {
_THREAD_SAFE_METHOD_
TS->shaped_text_set_bidi_override(rid, p_override);
lines_dirty = true;
}
bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
lines_dirty = true;
return res;
}
bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
_THREAD_SAFE_METHOD_
bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
lines_dirty = true;
return res;
}
void TextParagraph::set_alignment(HorizontalAlignment p_alignment) {
_THREAD_SAFE_METHOD_
if (alignment != p_alignment) {
if (alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
alignment = p_alignment;
@ -394,11 +432,15 @@ HorizontalAlignment TextParagraph::get_alignment() const {
}
void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
_THREAD_SAFE_METHOD_
tab_stops = p_tab_stops;
lines_dirty = true;
}
void TextParagraph::set_flags(uint16_t p_flags) {
_THREAD_SAFE_METHOD_
if (flags != p_flags) {
flags = p_flags;
lines_dirty = true;
@ -410,6 +452,8 @@ uint16_t TextParagraph::get_flags() const {
}
void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
_THREAD_SAFE_METHOD_
if (overrun_behavior != p_behavior) {
overrun_behavior = p_behavior;
lines_dirty = true;
@ -421,6 +465,8 @@ TextParagraph::OverrunBehavior TextParagraph::get_text_overrun_behavior() const
}
void TextParagraph::set_width(float p_width) {
_THREAD_SAFE_METHOD_
if (width != p_width) {
width = p_width;
lines_dirty = true;
@ -432,6 +478,8 @@ float TextParagraph::get_width() const {
}
Size2 TextParagraph::get_non_wrapped_size() const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
@ -441,9 +489,11 @@ Size2 TextParagraph::get_non_wrapped_size() const {
}
Size2 TextParagraph::get_size() const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
Size2 size;
int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
for (int i = 0; i < visible_lines; i++) {
Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
@ -458,11 +508,15 @@ Size2 TextParagraph::get_size() const {
}
int TextParagraph::get_line_count() const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
return lines_rid.size();
return (int)lines_rid.size();
}
void TextParagraph::set_max_lines_visible(int p_lines) {
_THREAD_SAFE_METHOD_
if (p_lines != max_lines_visible) {
max_lines_visible = p_lines;
lines_dirty = true;
@ -474,14 +528,18 @@ int TextParagraph::get_max_lines_visible() const {
}
Array TextParagraph::get_line_objects(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Array());
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Array());
return TS->shaped_text_get_objects(lines_rid[p_line]);
}
Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Rect2());
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Rect2());
Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
for (int i = 0; i < p_line; i++) {
Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
@ -495,8 +553,10 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
}
Size2 TextParagraph::get_line_size(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Size2());
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Size2());
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y + spacing_top + spacing_bottom);
} else {
@ -505,42 +565,56 @@ Size2 TextParagraph::get_line_size(int p_line) const {
}
Vector2i TextParagraph::get_line_range(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Vector2i());
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Vector2i());
return TS->shaped_text_get_range(lines_rid[p_line]);
}
float TextParagraph::get_line_ascent(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
}
float TextParagraph::get_line_descent(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_descent(lines_rid[p_line]) + spacing_bottom;
}
float TextParagraph::get_line_width(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_width(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_position(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_underline_position(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_thickness(int p_line) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
return TS->shaped_text_get_underline_thickness(lines_rid[p_line]);
}
Size2 TextParagraph::get_dropcap_size() const {
_THREAD_SAFE_METHOD_
return TS->shaped_text_get_size(dropcap_rid) + dropcap_margins.size + dropcap_margins.position;
}
@ -549,6 +623,8 @@ int TextParagraph::get_dropcap_lines() const {
}
void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs = p_pos;
float h_offset = 0.f;
@ -571,7 +647,7 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color);
}
int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
for (int i = 0; i < lines_visible; i++) {
float l_width = width;
@ -650,6 +726,8 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
}
void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs = p_pos;
@ -673,7 +751,7 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color);
}
for (int i = 0; i < lines_rid.size(); i++) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
@ -750,6 +828,8 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
}
int TextParagraph::hit_test(const Point2 &p_coords) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
@ -761,7 +841,7 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
return 0;
}
}
for (int i = 0; i < lines_rid.size(); i++) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines_rid[i]).y)) {
return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.x);
@ -778,6 +858,8 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
}
void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const {
_THREAD_SAFE_METHOD_
Vector2 ofs = p_pos;
float h_offset = 0.f;
if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@ -800,6 +882,8 @@ void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color
}
void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const {
_THREAD_SAFE_METHOD_
Vector2 ofs = p_pos;
float h_offset = 0.f;
if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@ -822,8 +906,10 @@ void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int
}
void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
Vector2 ofs = p_pos;
@ -836,8 +922,10 @@ void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, co
}
void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color) const {
_THREAD_SAFE_METHOD_
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
Vector2 ofs = p_pos;
if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
@ -862,7 +950,7 @@ TextParagraph::TextParagraph() {
}
TextParagraph::~TextParagraph() {
for (int i = 0; i < lines_rid.size(); i++) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();

View file

@ -31,6 +31,7 @@
#ifndef TEXT_PARAGRAPH_H
#define TEXT_PARAGRAPH_H
#include "core/templates/local_vector.h"
#include "scene/resources/font.h"
#include "servers/text_server.h"
@ -38,6 +39,7 @@
class TextParagraph : public RefCounted {
GDCLASS(TextParagraph, RefCounted);
_THREAD_SAFE_CLASS_
public:
enum OverrunBehavior {
@ -54,7 +56,7 @@ private:
Rect2 dropcap_margins;
RID rid;
Vector<RID> lines_rid;
LocalVector<RID> lines_rid;
int spacing_top = 0;
int spacing_bottom = 0;
@ -156,6 +158,8 @@ public:
int hit_test(const Point2 &p_coords) const;
Mutex &get_mutex() const { return _thread_safe_; };
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();