[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

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();