diff options
Diffstat (limited to 'servers')
-rw-r--r-- | servers/text_server.cpp | 88 | ||||
-rw-r--r-- | servers/text_server.h | 22 |
2 files changed, 105 insertions, 5 deletions
diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 1491368109..c5b685240f 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -739,6 +739,11 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped, int p_gra 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); @@ -976,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++) { @@ -1137,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++) { @@ -1170,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)) { @@ -1182,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++) { @@ -1220,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); } @@ -1230,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) { diff --git a/servers/text_server.h b/servers/text_server.h index 4c2ada7fc9..deac7cc96e 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -59,7 +59,8 @@ public: JUSTIFICATION_KASHIDA = 1 << 0, JUSTIFICATION_WORD_BOUND = 1 << 1, JUSTIFICATION_TRIM_EDGE_SPACES = 1 << 2, - JUSTIFICATION_AFTER_LAST_TAB = 1 << 3 + JUSTIFICATION_AFTER_LAST_TAB = 1 << 3, + JUSTIFICATION_CONSTRAIN_ELLIPSIS = 1 << 4, }; enum LineBreakFlag { @@ -67,7 +68,7 @@ public: BREAK_MANDATORY = 1 << 4, BREAK_WORD_BOUND = 1 << 5, BREAK_GRAPHEME_BOUND = 1 << 6, - BREAK_WORD_BOUND_ADAPTIVE = 1 << 5 | 1 << 7 + BREAK_WORD_BOUND_ADAPTIVE = 1 << 5 | 1 << 7, }; enum TextOverrunFlag { @@ -75,7 +76,8 @@ public: OVERRUN_TRIM = 1 << 0, OVERRUN_TRIM_WORD_ONLY = 1 << 1, OVERRUN_ADD_ELLIPSIS = 1 << 2, - OVERRUN_ENFORCE_ELLIPSIS = 1 << 3 + OVERRUN_ENFORCE_ELLIPSIS = 1 << 3, + OVERRUN_JUSTIFICATION_AWARE = 1 << 4, }; enum GraphemeFlag { @@ -154,6 +156,12 @@ public: } }; + struct TrimData { + int trim_pos = -1; + int ellipsis_pos = -1; + Vector<TextServer::Glyph> ellipsis_glyph_buf; + }; + struct ShapedTextData { /* Source data */ RID parent; // Substring parent ShapedTextData. @@ -192,6 +200,7 @@ public: bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. bool sort_valid = false; + bool text_trimmed = false; bool preserve_invalid = true; // Draw hex code box instead of missing characters. bool preserve_control = false; // Draw control characters. @@ -199,10 +208,14 @@ public: 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; float upos = 0.f; float uthk = 0.f; + TrimData overrun_trim_data; + bool fit_width_minimum_reached = false; + Vector<TextServer::Glyph> glyphs; Vector<TextServer::Glyph> glyphs_logical; }; @@ -357,7 +370,8 @@ public: virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, float 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 void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) = 0; + virtual TrimData shaped_text_get_trim_data(RID p_shaped) const; + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) = 0; virtual Array shaped_text_get_objects(RID p_shaped) const = 0; virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const = 0; |