|
@@ -4218,15 +4218,14 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < parent->spans.size(); i++) {
|
|
|
+ for (int i = p_shaped->first_span; i <= p_shaped->last_span; i++) {
|
|
|
ShapedTextDataAdvanced::Span span = parent->spans[i];
|
|
|
- if (span.start >= p_shaped->end || span.end <= p_shaped->start) {
|
|
|
- continue;
|
|
|
- }
|
|
|
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();
|
|
|
}
|
|
@@ -4252,6 +4251,8 @@ void TextServerAdvanced::_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();
|
|
|
sd->bidi_override.clear();
|
|
|
invalidate(sd, true);
|
|
@@ -4436,19 +4437,48 @@ TextServer::Orientation TextServerAdvanced::_shaped_text_get_orientation(const R
|
|
|
int64_t TextServerAdvanced::_shaped_get_span_count(const RID &p_shaped) const {
|
|
|
ShapedTextDataAdvanced *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 TextServerAdvanced::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
|
|
|
ShapedTextDataAdvanced *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()) {
|
|
|
+ ShapedTextDataAdvanced *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 TextServerAdvanced::_shaped_get_span_embedded_object(const RID &p_shaped, int64_t p_index) const {
|
|
|
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
|
|
|
+ ERR_FAIL_NULL_V(sd, Variant());
|
|
|
+ if (sd->parent != RID()) {
|
|
|
+ ShapedTextDataAdvanced *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 TextServerAdvanced::_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) {
|
|
|
ShapedTextDataAdvanced *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());
|
|
|
|
|
|
ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index];
|
|
@@ -4542,18 +4572,22 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V
|
|
|
sd->width = 0;
|
|
|
sd->upos = 0;
|
|
|
sd->uthk = 0;
|
|
|
+
|
|
|
+ Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;
|
|
|
+ if (sd->parent != RID()) {
|
|
|
+ ShapedTextDataAdvanced *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, ShapedTextDataAdvanced::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) {
|
|
@@ -4724,6 +4758,20 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
|
|
|
p_new_sd->utf16 = p_new_sd->text.utf16();
|
|
|
p_new_sd->script_iter = memnew(ScriptIterator(p_new_sd->text, 0, p_new_sd->text.length()));
|
|
|
|
|
|
+ int span_size = p_sd->spans.size();
|
|
|
+
|
|
|
+ p_new_sd->first_span = 0;
|
|
|
+ p_new_sd->last_span = span_size - 1;
|
|
|
+ for (int i = 0; i < span_size; i++) {
|
|
|
+ const ShapedTextDataAdvanced::Span &span = p_sd->spans[i];
|
|
|
+ if (span.end <= p_start) {
|
|
|
+ p_new_sd->first_span = i + 1;
|
|
|
+ } else if (span.start >= p_start + p_length) {
|
|
|
+ p_new_sd->last_span = i - 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
int sd_size = p_sd->glyphs.size();
|
|
|
const Glyph *sd_glyphs = p_sd->glyphs.ptr();
|
|
|
for (int ov = 0; ov < p_sd->bidi_override.size(); ov++) {
|
|
@@ -4802,31 +4850,27 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
|
|
|
if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
|
|
|
// Copy glyphs.
|
|
|
Glyph gl = sd_glyphs[j];
|
|
|
+ if (gl.span_index >= 0) {
|
|
|
+ gl.span_index -= p_new_sd->first_span;
|
|
|
+ }
|
|
|
if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {
|
|
|
uint32_t index = font_get_glyph_index(gl.font_rid, gl.font_size, 0x00ad, 0);
|
|
|
float w = font_get_glyph_advance(gl.font_rid, gl.font_size, index)[(p_new_sd->orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];
|
|
|
gl.index = index;
|
|
|
gl.advance = w;
|
|
|
}
|
|
|
- Variant key;
|
|
|
- bool find_embedded = false;
|
|
|
- if (gl.count == 1) {
|
|
|
- for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) {
|
|
|
- if (E.value.start == gl.start) {
|
|
|
- find_embedded = true;
|
|
|
- key = E.key;
|
|
|
- p_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 = p_sd->spans[gl.span_index].embedded_key;
|
|
|
+ if (key != Variant()) {
|
|
|
+ ShapedTextDataAdvanced::EmbeddedObject obj = p_sd->objects[key];
|
|
|
+ if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
|
|
+ obj.rect.position.x = p_new_sd->width;
|
|
|
+ p_new_sd->width += obj.rect.size.x;
|
|
|
+ } else {
|
|
|
+ obj.rect.position.y = p_new_sd->width;
|
|
|
+ p_new_sd->width += obj.rect.size.y;
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
- if (find_embedded) {
|
|
|
- if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
|
|
- p_new_sd->objects[key].rect.position.x = p_new_sd->width;
|
|
|
- p_new_sd->width += p_new_sd->objects[key].rect.size.x;
|
|
|
- } else {
|
|
|
- p_new_sd->objects[key].rect.position.y = p_new_sd->width;
|
|
|
- p_new_sd->width += p_new_sd->objects[key].rect.size.y;
|
|
|
+ p_new_sd->objects[key] = obj;
|
|
|
}
|
|
|
} else {
|
|
|
if (gl.font_rid.is_valid()) {
|
|
@@ -5284,7 +5328,8 @@ void TextServerAdvanced::_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;
|
|
|
}
|
|
|
|
|
@@ -5296,7 +5341,7 @@ void TextServerAdvanced::_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];
|
|
@@ -5306,7 +5351,7 @@ void TextServerAdvanced::_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;
|
|
@@ -5319,7 +5364,7 @@ void TextServerAdvanced::_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];
|
|
@@ -5328,7 +5373,7 @@ void TextServerAdvanced::_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;
|
|
|
}
|
|
@@ -5338,7 +5383,7 @@ void TextServerAdvanced::_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];
|
|
@@ -5497,7 +5542,8 @@ void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const {
|
|
|
spans = parent_sd->spans;
|
|
|
}
|
|
|
|
|
|
- while (i < spans.size()) {
|
|
|
+ int span_size = spans.size();
|
|
|
+ while (i < span_size) {
|
|
|
if (spans[i].start > p_sd->end) {
|
|
|
break;
|
|
|
}
|
|
@@ -5508,7 +5554,7 @@ void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const {
|
|
|
|
|
|
int r_start = MAX(0, spans[i].start - p_sd->start);
|
|
|
String language = spans[i].language;
|
|
|
- while (i + 1 < spans.size() && language == spans[i + 1].language) {
|
|
|
+ while (i + 1 < span_size && language == spans[i + 1].language) {
|
|
|
i++;
|
|
|
}
|
|
|
int r_end = MIN(spans[i].end - p_sd->start, p_sd->text.length());
|
|
@@ -5570,10 +5616,11 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
|
|
|
sd->break_inserts = 0;
|
|
|
UErrorCode err = U_ZERO_ERROR;
|
|
|
int i = 0;
|
|
|
- while (i < sd->spans.size()) {
|
|
|
+ int span_size = sd->spans.size();
|
|
|
+ while (i < span_size) {
|
|
|
String language = sd->spans[i].language;
|
|
|
int r_start = sd->spans[i].start;
|
|
|
- while (i + 1 < sd->spans.size() && language == sd->spans[i + 1].language) {
|
|
|
+ while (i + 1 < span_size && language == sd->spans[i + 1].language) {
|
|
|
i++;
|
|
|
}
|
|
|
int r_end = sd->spans[i].end;
|
|
@@ -5697,6 +5744,7 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
|
|
|
}
|
|
|
}
|
|
|
Glyph gl;
|
|
|
+ gl.span_index = sd_glyphs[i].span_index;
|
|
|
gl.start = sd_glyphs[i].start;
|
|
|
gl.end = sd_glyphs[i].end;
|
|
|
gl.count = 1;
|
|
@@ -5945,6 +5993,7 @@ bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shap
|
|
|
}
|
|
|
// Inject virtual space for alignment.
|
|
|
Glyph gl;
|
|
|
+ gl.span_index = sd_glyphs[i].span_index;
|
|
|
gl.start = sd_glyphs[i].start;
|
|
|
gl.end = sd_glyphs[i].end;
|
|
|
gl.count = 1;
|
|
@@ -6091,6 +6140,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
|
|
|
for (int i = fb_from; i != fb_to; i += fb_delta) {
|
|
|
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
|
|
|
Glyph gl;
|
|
|
+ gl.span_index = p_span;
|
|
|
gl.start = i + p_sd->start;
|
|
|
gl.end = i + 1 + p_sd->start;
|
|
|
gl.count = 1;
|
|
@@ -6247,6 +6297,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
|
|
|
Glyph &gl = w[i];
|
|
|
gl = Glyph();
|
|
|
|
|
|
+ gl.span_index = p_span;
|
|
|
gl.start = glyph_info[i].cluster;
|
|
|
gl.end = end;
|
|
|
gl.count = 0;
|
|
@@ -6556,6 +6607,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
|
|
|
gl.start = span.start;
|
|
|
gl.end = span.end;
|
|
|
gl.count = 1;
|
|
|
+ gl.span_index = k;
|
|
|
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;
|
|
|
if (sd->orientation == ORIENTATION_HORIZONTAL) {
|
|
|
gl.advance = sd->objects[span.embedded_key].rect.size.x;
|