1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-12 13:20:55 +00:00

[TextServer] Improve embedded objects handling performance.

This commit is contained in:
bruvzg
2024-09-26 09:37:47 +03:00
committed by Pāvels Nadtočajevs
parent 4cf02312f6
commit cc1db569e1
15 changed files with 242 additions and 89 deletions

View File

@@ -3087,15 +3087,14 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
}
}
for (int k = 0; k < parent->spans.size(); k++) {
ShapedTextDataFallback::Span span = parent->spans[k];
if (span.start >= p_shaped->end || span.end <= p_shaped->start) {
continue;
}
for (int i = p_shaped->first_span; i <= p_shaped->last_span; i++) {
ShapedTextDataFallback::Span span = parent->spans[i];
span.start = MAX(p_shaped->start, span.start);
span.end = MIN(p_shaped->end, span.end);
p_shaped->spans.push_back(span);
}
p_shaped->first_span = 0;
p_shaped->last_span = 0;
p_shaped->parent = RID();
}
@@ -3121,6 +3120,8 @@ void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {
sd->end = 0;
sd->text = String();
sd->spans.clear();
sd->first_span = 0;
sd->last_span = 0;
sd->objects.clear();
invalidate(sd);
}
@@ -3273,19 +3274,48 @@ int64_t TextServerFallback::_shaped_text_get_spacing(const RID &p_shaped, Spacin
int64_t TextServerFallback::_shaped_get_span_count(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, 0);
return sd->spans.size();
if (sd->parent != RID()) {
return sd->last_span - sd->first_span + 1;
} else {
return sd->spans.size();
}
}
Variant TextServerFallback::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, Variant());
ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
return sd->spans[p_index].meta;
if (sd->parent != RID()) {
ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);
ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());
ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());
return parent_sd->spans[p_index + sd->first_span].meta;
} else {
ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
return sd->spans[p_index].meta;
}
}
Variant TextServerFallback::_shaped_get_span_embedded_object(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, Variant());
if (sd->parent != RID()) {
ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);
ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());
ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());
return parent_sd->spans[p_index + sd->first_span].embedded_key;
} else {
ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
return sd->spans[p_index].embedded_key;
}
}
void TextServerFallback::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL(sd);
if (sd->parent != RID()) {
full_copy(sd);
}
ERR_FAIL_INDEX(p_index, sd->spans.size());
ShapedTextDataFallback::Span &span = sd->spans.ptrw()[p_index];
@@ -3407,18 +3437,22 @@ bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const V
sd->width = 0;
sd->upos = 0;
sd->uthk = 0;
Vector<ShapedTextDataFallback::Span> &spans = sd->spans;
if (sd->parent != RID()) {
ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);
ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);
spans = parent_sd->spans;
}
int sd_size = sd->glyphs.size();
int span_size = spans.size();
for (int i = 0; i < sd_size; i++) {
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) {
if (E.value.start == gl.start) {
key = E.key;
break;
}
}
if ((gl.flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && gl.span_index + sd->first_span >= 0 && gl.span_index + sd->first_span < span_size) {
key = spans[gl.span_index + sd->first_span].embedded_key;
}
if (key != Variant()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -3570,35 +3604,46 @@ RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start
if (p_length > 0) {
new_sd->text = sd->text.substr(p_start - sd->start, p_length);
int span_size = sd->spans.size();
new_sd->first_span = 0;
new_sd->last_span = span_size - 1;
for (int i = 0; i < span_size; i++) {
const ShapedTextDataFallback::Span &span = sd->spans[i];
if (span.end <= p_start) {
new_sd->first_span = i + 1;
} else if (span.start >= p_start + p_length) {
new_sd->last_span = i - 1;
break;
}
}
int sd_size = sd->glyphs.size();
const Glyph *sd_glyphs = sd->glyphs.ptr();
for (int i = 0; i < sd_size; i++) {
if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {
Glyph gl = sd_glyphs[i];
if (gl.span_index >= 0) {
gl.span_index -= new_sd->first_span;
}
if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {
gl.index = 0x00ad;
gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, 0x00ad).x;
}
Variant key;
bool find_embedded = false;
if (gl.count == 1) {
for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) {
if (E.value.start == gl.start) {
find_embedded = true;
key = E.key;
new_sd->objects[key] = E.value;
break;
if ((gl.flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && gl.span_index >= 0 && gl.span_index < span_size) {
Variant key = sd->spans[gl.span_index].embedded_key;
if (key != Variant()) {
ShapedTextDataFallback::EmbeddedObject obj = sd->objects[key];
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
obj.rect.position.x = new_sd->width;
new_sd->width += obj.rect.size.x;
} else {
obj.rect.position.y = new_sd->width;
new_sd->width += obj.rect.size.y;
}
}
}
if (find_embedded) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
} else {
new_sd->objects[key].rect.position.y = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.y;
new_sd->objects[key] = obj;
}
} else {
if (gl.font_rid.is_valid()) {
@@ -4088,7 +4133,8 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
spans = parent_sd->spans;
}
if (spans.size() == 0) {
int span_size = spans.size();
if (span_size == 0) {
return;
}
@@ -4100,7 +4146,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
if (add_ellipsis || enforce_ellipsis) {
if (!_font_has_char(dot_gl_font_rid, sd->el_char)) {
const Array &fonts = spans[spans.size() - 1].fonts;
const Array &fonts = spans[span_size - 1].fonts;
for (int i = 0; i < fonts.size(); i++) {
if (_font_has_char(fonts[i], sd->el_char)) {
dot_gl_font_rid = fonts[i];
@@ -4110,7 +4156,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
}
if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {
const char32_t u32str[] = { sd->el_char, 0 };
RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, u32str);
RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, u32str);
if (rid.is_valid()) {
dot_gl_font_rid = rid;
found_el_char = true;
@@ -4123,7 +4169,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
bool found_dot_char = false;
dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
if (!_font_has_char(dot_gl_font_rid, '.')) {
const Array &fonts = spans[spans.size() - 1].fonts;
const Array &fonts = spans[span_size - 1].fonts;
for (int i = 0; i < fonts.size(); i++) {
if (_font_has_char(fonts[i], '.')) {
dot_gl_font_rid = fonts[i];
@@ -4132,7 +4178,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
}
}
if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {
RID rid = _find_sys_font_for_text(fonts[0], String(), spans[spans.size() - 1].language, ".");
RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, ".");
if (rid.is_valid()) {
dot_gl_font_rid = rid;
}
@@ -4142,7 +4188,7 @@ void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_
}
RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
if (!_font_has_char(whitespace_gl_font_rid, ' ')) {
const Array &fonts = spans[spans.size() - 1].fonts;
const Array &fonts = spans[span_size - 1].fonts;
for (int i = 0; i < fonts.size(); i++) {
if (_font_has_char(fonts[i], ' ')) {
whitespace_gl_font_rid = fonts[i];
@@ -4314,6 +4360,7 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {
sd->width += sd->objects[span.embedded_key].rect.size.y;
}
Glyph gl;
gl.span_index = i;
gl.start = span.start;
gl.end = span.end;
gl.count = 1;
@@ -4330,6 +4377,7 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {
RID prev_font;
for (int j = span.start; j < span.end; j++) {
Glyph gl;
gl.span_index = i;
gl.start = j;
gl.end = j + 1;
gl.count = 1;