You've already forked godot
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:
committed by
Pāvels Nadtočajevs
parent
4cf02312f6
commit
cc1db569e1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user