summaryrefslogtreecommitdiff
path: root/servers/text_server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/text_server.cpp')
-rw-r--r--servers/text_server.cpp129
1 files changed, 116 insertions, 13 deletions
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 8b03565291..6bace8cf9e 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -314,8 +314,8 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control", "shaped"), &TextServer::shaped_text_get_preserve_control);
ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL(""));
- ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1));
- ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(VALIGN_CENTER));
+ ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGN_CENTER));
ClassDB::bind_method(D_METHOD("shaped_text_substr", "shaped", "start", "length"), &TextServer::shaped_text_substr);
ClassDB::bind_method(D_METHOD("shaped_text_get_parent", "shaped"), &TextServer::shaped_text_get_parent);
@@ -331,6 +331,9 @@ void TextServer::_bind_methods() {
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_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_get_objects", "shaped"), &TextServer::shaped_text_get_objects);
ClassDB::bind_method(D_METHOD("shaped_text_get_object_rect", "shaped", "key"), &TextServer::shaped_text_get_object_rect);
@@ -381,6 +384,13 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(BREAK_WORD_BOUND);
BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND);
+ /* TextOverrunFlag */
+ BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ONLY);
+ BIND_ENUM_CONSTANT(OVERRUN_ADD_ELLIPSIS);
+ BIND_ENUM_CONSTANT(OVERRUN_ENFORCE_ELLIPSIS);
+
/* GraphemeFlag */
BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL);
BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL);
@@ -466,16 +476,16 @@ void TextServer::initialize_hex_code_box_fonts() {
Vector<uint8_t> hex_box_data;
Ref<Image> image;
- image.instance();
+ image.instantiate();
Ref<ImageTexture> hex_code_image_tex[2];
hex_box_data.resize(tamsyn5x9_png_len);
memcpy(hex_box_data.ptrw(), tamsyn5x9_png, tamsyn5x9_png_len);
image->load_png_from_buffer(hex_box_data);
- hex_code_image_tex[0].instance();
+ hex_code_image_tex[0].instantiate();
hex_code_image_tex[0]->create_from_image(image);
- hex_code_box_font_tex[0].instance();
+ hex_code_box_font_tex[0].instantiate();
hex_code_box_font_tex[0]->set_diffuse_texture(hex_code_image_tex[0]);
hex_code_box_font_tex[0]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
hex_box_data.clear();
@@ -483,9 +493,9 @@ void TextServer::initialize_hex_code_box_fonts() {
hex_box_data.resize(tamsyn10x20_png_len);
memcpy(hex_box_data.ptrw(), tamsyn10x20_png, tamsyn10x20_png_len);
image->load_png_from_buffer(hex_box_data);
- hex_code_image_tex[1].instance();
+ hex_code_image_tex[1].instantiate();
hex_code_image_tex[1]->create_from_image(image);
- hex_code_box_font_tex[1].instance();
+ hex_code_box_font_tex[1].instantiate();
hex_code_box_font_tex[1]->set_diffuse_texture(hex_code_image_tex[1]);
hex_code_box_font_tex[1]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
hex_box_data.clear();
@@ -646,7 +656,7 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
float width = 0.f;
int line_start = MAX(p_start, range.x);
int last_safe_break = -1;
-
+ int word_count = 0;
int l_size = logical.size();
const Glyph *l_gl = logical.ptr();
@@ -655,12 +665,15 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
continue;
}
if (l_gl[i].count > 0) {
- if ((p_width > 0) && (width + l_gl[i].advance > p_width) && (last_safe_break >= 0)) {
+ //Ignore trailing spaces.
+ bool is_space = (l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE;
+ if ((p_width > 0) && (width + (is_space ? 0 : l_gl[i].advance) > p_width) && (last_safe_break >= 0)) {
lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end));
line_start = l_gl[last_safe_break].end;
i = last_safe_break;
last_safe_break = -1;
width = 0;
+ word_count = 0;
continue;
}
if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
@@ -675,8 +688,12 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) {
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
last_safe_break = i;
+ word_count++;
}
}
+ if (((p_break_flags & BREAK_WORD_BOUND_ADAPTIVE) == BREAK_WORD_BOUND_ADAPTIVE) && word_count == 0) {
+ last_safe_break = i;
+ }
if ((p_break_flags & BREAK_GRAPHEME_BOUND) == BREAK_GRAPHEME_BOUND) {
last_safe_break = i;
}
@@ -695,7 +712,7 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
return lines;
}
-Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
+Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const {
Vector<Vector2i> words;
const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped);
@@ -709,7 +726,7 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
for (int i = 0; i < l_size; i++) {
if (l_gl[i].count > 0) {
- if (((l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) || ((l_gl[i].flags & GRAPHEME_IS_PUNCTUATION) == GRAPHEME_IS_PUNCTUATION)) {
+ if ((l_gl[i].flags & p_grapheme_flags) != 0) {
words.push_back(Vector2i(word_start, l_gl[i].start));
word_start = l_gl[i].end;
}
@@ -722,6 +739,11 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
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 {
Vector<Rect2> carets;
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
@@ -959,7 +981,7 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - start), off + advance));
}
}
- // Selection range is within grapheme
+ // Selection range is within grapheme.
if (glyphs[i].start < start && glyphs[i].end > end) {
float advance = 0.f;
for (int j = 0; j < glyphs[i].count; j++) {
@@ -987,7 +1009,7 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
while (i < ranges.size()) {
int j = i + 1;
while (j < ranges.size()) {
- if (Math::is_equal_approx(ranges[i].y, ranges[j].x, UNIT_EPSILON)) {
+ if (Math::is_equal_approx(ranges[i].y, ranges[j].x, (real_t)UNIT_EPSILON)) {
ranges.write[i].y = ranges[j].y;
ranges.remove(j);
continue;
@@ -1120,10 +1142,26 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped);
+ bool rtl = shaped_text_get_direction(p_shaped) == DIRECTION_RTL;
+ TrimData trim_data = shaped_text_get_trim_data(p_shaped);
+
int v_size = visual.size();
const Glyph *glyphs = visual.ptr();
Vector2 ofs = p_pos;
+ // Draw RTL ellipsis string when needed.
+ if (rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
// Draw at the baseline.
for (int i = 0; i < v_size; i++) {
for (int j = 0; j < glyphs[i].repeat; j++) {
@@ -1153,6 +1191,18 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
}
}
}
+ if (trim_data.trim_pos >= 0) {
+ if (rtl) {
+ if (i < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ continue;
+ }
+ } else {
+ if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ break;
+ }
+ }
+ }
+
if (glyphs[i].font_rid != RID()) {
font_draw_glyph(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color);
} else if (hex_codes && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
@@ -1165,15 +1215,44 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
}
}
}
+ // Draw LTR ellipsis string when needed.
+ if (!rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
}
void TextServer::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 {
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
+ bool rtl = (shaped_text_get_direction(p_shaped) == DIRECTION_RTL);
+ TrimData trim_data = shaped_text_get_trim_data(p_shaped);
+
int v_size = visual.size();
const Glyph *glyphs = visual.ptr();
Vector2 ofs = p_pos;
+ // Draw RTL ellipsis string when needed.
+ if (rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
// Draw at the baseline.
for (int i = 0; i < v_size; i++) {
for (int j = 0; j < glyphs[i].repeat; j++) {
@@ -1203,6 +1282,17 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect
}
}
}
+ if (trim_data.trim_pos >= 0) {
+ if (rtl) {
+ if (i < trim_data.trim_pos) {
+ continue;
+ }
+ } else {
+ if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ break;
+ }
+ }
+ }
if (glyphs[i].font_rid != RID()) {
font_draw_glyph_outline(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, p_outline_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color);
}
@@ -1213,6 +1303,19 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect
}
}
}
+ // Draw LTR ellipsis string when needed.
+ if (!rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
}
RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size) {