diff options
author | Hendrik Brucker <hendrik.brucker@mail.de> | 2021-08-11 00:09:48 +0200 |
---|---|---|
committer | Hendrik Brucker <hendrik.brucker@mail.de> | 2021-08-11 00:09:48 +0200 |
commit | 403f4902d02e70eebb684a199a8e2f14d4534ac0 (patch) | |
tree | 0ac36dad6c57d6d60540ea0dcf32a607ca7bde18 /modules/text_server_fb | |
parent | 33fd41472c7fb54280144fe46326cd6ffe9fc8af (diff) |
Various text layout improvements (TextLine, TextParagraph, Label, TextServer)
Diffstat (limited to 'modules/text_server_fb')
-rw-r--r-- | modules/text_server_fb/text_server_fb.cpp | 133 | ||||
-rw-r--r-- | modules/text_server_fb/text_server_fb.h | 3 |
2 files changed, 52 insertions, 84 deletions
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 004cbc2bb3..99f391cda7 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -570,7 +570,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) { - //No BiDi support, ignore. + // No BiDi support, ignore. } TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_shaped) const { @@ -1148,7 +1148,7 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) { return true; } -void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) { +void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_trim_flags) { _THREAD_SAFE_METHOD_ ShapedTextData *sd = shaped_owner.getornull(p_shaped_line); ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid."); @@ -1156,13 +1156,22 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl shaped_text_shape(p_shaped_line); } - bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS; - bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY; - bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS; + sd->overrun_trim_data.ellipsis_glyph_buf.clear(); + + bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS; + bool cut_per_word = (p_trim_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY; + bool enforce_ellipsis = (p_trim_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS; + bool justification_aware = (p_trim_flags & OVERRUN_JUSTIFICATION_AWARE) == OVERRUN_JUSTIFICATION_AWARE; Glyph *sd_glyphs = sd->glyphs.ptrw(); - if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { + if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { + sd->overrun_trim_data.trim_pos = -1; + sd->overrun_trim_data.ellipsis_pos = -1; + return; + } + + if (justification_aware && !sd->fit_width_minimum_reached) { return; } @@ -1174,34 +1183,27 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' '); Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size); - int ellipsis_advance = 0; + int ellipsis_width = 0; if (add_ellipsis) { - ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0); + ellipsis_width = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0); } int ell_min_characters = 6; float width = sd->width; - bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL); - - int trim_pos = (is_rtl) ? sd_size : 0; + int trim_pos = 0; int ellipsis_pos = (enforce_ellipsis) ? 0 : -1; int last_valid_cut = 0; bool found = false; - int glyphs_from = (is_rtl) ? 0 : sd_size - 1; - int glyphs_to = (is_rtl) ? sd_size - 1 : -1; - int glyphs_delta = (is_rtl) ? +1 : -1; + for (int i = sd_size - 1; i != -1; i--) { + width -= sd_glyphs[i].advance * sd_glyphs[i].repeat; - for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) { - if (!is_rtl) { - width -= sd_glyphs[i].advance; - } if (sd_glyphs[i].count > 0) { - bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters; + bool above_min_char_treshold = (i >= ell_min_characters); - if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) { + if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) { if (cut_per_word && above_min_char_treshold) { if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { last_valid_cut = i; @@ -1214,95 +1216,60 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl if (found) { trim_pos = last_valid_cut; - if (above_min_char_treshold && width - ellipsis_advance <= p_width) { + if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) { ellipsis_pos = trim_pos; } break; } } } - if (is_rtl) { - width -= sd_glyphs[i].advance; - } + } + + sd->overrun_trim_data.trim_pos = trim_pos; + sd->overrun_trim_data.ellipsis_pos = ellipsis_pos; + if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) { + sd->overrun_trim_data.ellipsis_pos = 0; } if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) { - int added_glyphs = 0; if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) { // Insert an additional space when cutting word bound for aesthetics. if (cut_per_word && (ellipsis_pos > 0)) { TextServer::Glyph gl; - gl.start = sd_glyphs[ellipsis_pos].start; - gl.end = sd_glyphs[ellipsis_pos].end; gl.count = 1; gl.advance = whitespace_adv.x; gl.index = whitespace_gl_idx; gl.font_rid = last_gl_font_rid; gl.font_size = last_gl_font_size; - gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); + gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL; - // Optimized glyph insertion by replacing a glyph whenever possible. - int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs); - if (is_rtl) { - if (glyph_idx < 0) { - sd->glyphs.insert(0, gl); - } else { - sd->glyphs.set(glyph_idx, gl); - } - } else { - if (glyph_idx > (sd_size - 1)) { - sd->glyphs.append(gl); - } else { - sd->glyphs.set(glyph_idx, gl); - } - } - added_glyphs++; + sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); } // Add ellipsis dots. - for (int d = 0; d < 3; d++) { - TextServer::Glyph gl; - gl.start = sd_glyphs[ellipsis_pos].start; - gl.end = sd_glyphs[ellipsis_pos].end; - gl.count = 1; - gl.advance = dot_adv.x; - gl.index = dot_gl_idx; - gl.font_rid = last_gl_font_rid; - gl.font_size = last_gl_font_size; - gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0); - - // Optimized glyph insertion by replacing a glyph whenever possible. - int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs); - if (is_rtl) { - if (glyph_idx < 0) { - sd->glyphs.insert(0, gl); - } else { - sd->glyphs.set(glyph_idx, gl); - } - } else { - if (glyph_idx > (sd_size - 1)) { - sd->glyphs.append(gl); - } else { - sd->glyphs.set(glyph_idx, gl); - } - } - added_glyphs++; - } - } - - // Cut the remaining glyphs off. - if (!is_rtl) { - sd->glyphs.resize(trim_pos + added_glyphs); - } else { - for (int ridx = 0; ridx <= trim_pos - added_glyphs; ridx++) { - sd->glyphs.remove(0); - } + TextServer::Glyph gl; + gl.count = 1; + gl.repeat = 3; + gl.advance = dot_adv.x; + gl.index = dot_gl_idx; + gl.font_rid = last_gl_font_rid; + gl.font_size = last_gl_font_size; + gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL; + + sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); } - // Update to correct width. - sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0); + sd->text_trimmed = true; + sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0); } } +TextServer::TrimData TextServerFallback::shaped_text_get_trim_data(RID p_shaped) const { + _THREAD_SAFE_METHOD_ + ShapedTextData *sd = shaped_owner.getornull(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid."); + return sd->overrun_trim_data; +} + bool TextServerFallback::shaped_text_shape(RID p_shaped) { _THREAD_SAFE_METHOD_ ShapedTextData *sd = shaped_owner.getornull(p_shaped); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index b70c8f4ec0..e14759c679 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -178,7 +178,8 @@ public: 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, float p_width, uint8_t p_clip_flags) override; + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) override; + virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override; virtual bool shaped_text_is_ready(RID p_shaped) const override; |