diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 9a17fb3def5..bea503865cd 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1367,6 +1367,22 @@
Breaks text to the lines and columns. Returns character ranges for each segment.
+
+
+
+
+
+ Returns the glyph index of the inline object.
+
+
+
+
+
+
+
+ Returns the character range of the inline object.
+
+
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 5beb5797dbd..e95b2204840 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -1180,6 +1180,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 3da19aaee8c..4822c29613a 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -4000,7 +4000,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent);
for (const KeyValue &E : parent->objects) {
- if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) {
+ if (E.value.start >= p_shaped->start && E.value.start < p_shaped->end) {
p_shaped->objects[E.key] = E.value;
}
}
@@ -4300,7 +4300,8 @@ bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Vari
ShapedTextDataAdvanced::EmbeddedObject obj;
obj.inline_align = p_inline_align;
obj.rect.size = p_size;
- obj.pos = span.start;
+ obj.start = span.start;
+ obj.end = span.end;
obj.baseline = p_baseline;
sd->spans.push_back(span);
@@ -4335,7 +4336,7 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V
Variant key;
if (gl.count == 1) {
for (const KeyValue &E : sd->objects) {
- if (E.value.pos == gl.start) {
+ if (E.value.start == gl.start) {
key = E.key;
break;
}
@@ -4386,7 +4387,7 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
double full_ascent = p_sd->ascent;
double full_descent = p_sd->descent;
for (KeyValue &E : p_sd->objects) {
- if ((E.value.pos >= p_sd->start) && (E.value.pos < p_sd->end)) {
+ if ((E.value.start >= p_sd->start) && (E.value.start < p_sd->end)) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
case INLINE_ALIGNMENT_TO_TOP: {
@@ -4598,7 +4599,7 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
bool find_embedded = false;
if (gl.count == 1) {
for (const KeyValue &E : p_sd->objects) {
- if (E.value.pos == gl.start) {
+ if (E.value.start == gl.start) {
find_embedded = true;
key = E.key;
p_new_sd->objects[key] = E.value;
@@ -6437,6 +6438,35 @@ Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, cons
return sd->objects[p_key].rect;
}
+Vector2i TextServerAdvanced::_shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_NULL_V(sd, Vector2i());
+
+ MutexLock lock(sd->mutex);
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), Vector2i());
+ return Vector2i(sd->objects[p_key].start, sd->objects[p_key].end);
+}
+
+int64_t TextServerAdvanced::_shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_NULL_V(sd, -1);
+
+ MutexLock lock(sd->mutex);
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), -1);
+ if (!sd->valid) {
+ const_cast(this)->_shaped_text_shape(p_shaped);
+ }
+ const ShapedTextDataAdvanced::EmbeddedObject &obj = sd->objects[p_key];
+ int sd_size = sd->glyphs.size();
+ const Glyph *sd_glyphs = sd->glyphs.ptr();
+ for (int i = 0; i < sd_size; i++) {
+ if (obj.start == sd_glyphs[i].start) {
+ return i;
+ }
+ }
+ return -1;
+}
+
Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const {
const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, Size2());
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 3f04c17d9cb..9f70fdb0ef6 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -475,7 +475,8 @@ class TextServerAdvanced : public TextServerExtension {
Vector spans;
struct EmbeddedObject {
- int pos = 0;
+ int start = -1;
+ int end = -1;
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
double baseline = 0;
@@ -957,6 +958,8 @@ public:
MODBIND1RC(Array, shaped_text_get_objects, const RID &);
MODBIND2RC(Rect2, shaped_text_get_object_rect, const RID &, const Variant &);
+ MODBIND2RC(Vector2i, shaped_text_get_object_range, const RID &, const Variant &);
+ MODBIND2RC(int64_t, shaped_text_get_object_glyph, const RID &, const Variant &);
MODBIND1RC(Size2, shaped_text_get_size, const RID &);
MODBIND1RC(double, shaped_text_get_ascent, const RID &);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 7e34de0bbc6..10a73d3db18 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -2874,7 +2874,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
ShapedTextDataFallback *parent = shaped_owner.get_or_null(p_shaped->parent);
for (const KeyValue &E : parent->objects) {
- if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) {
+ if (E.value.start >= p_shaped->start && E.value.start < p_shaped->end) {
p_shaped->objects[E.key] = E.value;
}
}
@@ -3170,7 +3170,8 @@ bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Vari
ShapedTextDataFallback::EmbeddedObject obj;
obj.inline_align = p_inline_align;
obj.rect.size = p_size;
- obj.pos = span.start;
+ obj.start = span.start;
+ obj.end = span.end;
obj.baseline = p_baseline;
sd->spans.push_back(span);
@@ -3205,7 +3206,7 @@ bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const V
Variant key;
if (gl.count == 1) {
for (const KeyValue &E : sd->objects) {
- if (E.value.pos == gl.start) {
+ if (E.value.start == gl.start) {
key = E.key;
break;
}
@@ -3254,7 +3255,7 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
double full_ascent = p_sd->ascent;
double full_descent = p_sd->descent;
for (KeyValue &E : p_sd->objects) {
- if ((E.value.pos >= p_sd->start) && (E.value.pos < p_sd->end)) {
+ if ((E.value.start >= p_sd->start) && (E.value.start < p_sd->end)) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
case INLINE_ALIGNMENT_TO_TOP: {
@@ -3375,7 +3376,7 @@ RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start
bool find_embedded = false;
if (gl.count == 1) {
for (const KeyValue &E : sd->objects) {
- if (E.value.pos == gl.start) {
+ if (E.value.start == gl.start) {
find_embedded = true;
key = E.key;
new_sd->objects[key] = E.value;
@@ -4288,6 +4289,32 @@ Rect2 TextServerFallback::_shaped_text_get_object_rect(const RID &p_shaped, cons
return sd->objects[p_key].rect;
}
+Vector2i TextServerFallback::_shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {
+ const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_NULL_V(sd, Vector2i());
+
+ MutexLock lock(sd->mutex);
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), Vector2i());
+ return Vector2i(sd->objects[p_key].start, sd->objects[p_key].end);
+}
+
+int64_t TextServerFallback::_shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {
+ const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_NULL_V(sd, -1);
+
+ MutexLock lock(sd->mutex);
+ ERR_FAIL_COND_V(!sd->objects.has(p_key), -1);
+ const ShapedTextDataFallback::EmbeddedObject &obj = sd->objects[p_key];
+ int sd_size = sd->glyphs.size();
+ const Glyph *sd_glyphs = sd->glyphs.ptr();
+ for (int i = 0; i < sd_size; i++) {
+ if (obj.start == sd_glyphs[i].start) {
+ return i;
+ }
+ }
+ return -1;
+}
+
Size2 TextServerFallback::_shaped_text_get_size(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_NULL_V(sd, Size2());
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 9cdf20f3fab..401c02a8ac3 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -421,7 +421,8 @@ class TextServerFallback : public TextServerExtension {
Vector spans;
struct EmbeddedObject {
- int pos = 0;
+ int start = -1;
+ int end = -1;
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
double baseline = 0;
@@ -825,6 +826,8 @@ public:
MODBIND1RC(Array, shaped_text_get_objects, const RID &);
MODBIND2RC(Rect2, shaped_text_get_object_rect, const RID &, const Variant &);
+ MODBIND2RC(Vector2i, shaped_text_get_object_range, const RID &, const Variant &);
+ MODBIND2RC(int64_t, shaped_text_get_object_glyph, const RID &, const Variant &);
MODBIND1RC(Size2, shaped_text_get_size, const RID &);
MODBIND1RC(double, shaped_text_get_ascent, const RID &);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 5fe26aac069..cb7ccb583e8 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -935,6 +935,16 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
for (int i = 0; i < objects.size(); i++) {
Item *it = items.get_or_null(objects[i]);
if (it != nullptr) {
+ Vector2i obj_range = TS->shaped_text_get_object_range(rid, objects[i]);
+ if (trim_chars && l.char_offset + obj_range.y > visible_characters) {
+ continue;
+ }
+ if (trim_glyphs_ltr || trim_glyphs_rtl) {
+ int obj_glyph = r_processed_glyphs + TS->shaped_text_get_object_glyph(rid, objects[i]);
+ if ((trim_glyphs_ltr && (obj_glyph >= visible_glyphs)) || (trim_glyphs_rtl && (obj_glyph < total_glyphs - visible_glyphs))) {
+ continue;
+ }
+ }
Rect2 rect = TS->shaped_text_get_object_rect(rid, objects[i]);
//draw_rect(rect, Color(1,0,0), false, 2); //DEBUG_RECTS
switch (it->type) {
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index d5080e586d1..c8e87cc7fcd 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -293,6 +293,8 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_shaped_text_get_objects, "shaped");
GDVIRTUAL_BIND(_shaped_text_get_object_rect, "shaped", "key");
+ GDVIRTUAL_BIND(_shaped_text_get_object_range, "shaped", "key");
+ GDVIRTUAL_BIND(_shaped_text_get_object_glyph, "shaped", "key");
GDVIRTUAL_BIND(_shaped_text_get_size, "shaped");
GDVIRTUAL_BIND(_shaped_text_get_ascent, "shaped");
@@ -1284,6 +1286,18 @@ Rect2 TextServerExtension::shaped_text_get_object_rect(const RID &p_shaped, cons
return ret;
}
+Vector2i TextServerExtension::shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {
+ Vector2i ret;
+ GDVIRTUAL_CALL(_shaped_text_get_object_range, p_shaped, p_key, ret);
+ return ret;
+}
+
+int64_t TextServerExtension::shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {
+ int64_t ret = -1;
+ GDVIRTUAL_CALL(_shaped_text_get_object_glyph, p_shaped, p_key, ret);
+ return ret;
+}
+
Size2 TextServerExtension::shaped_text_get_size(const RID &p_shaped) const {
Size2 ret;
GDVIRTUAL_CALL(_shaped_text_get_size, p_shaped, ret);
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 4f9ea55d33d..bb786407893 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -486,8 +486,12 @@ public:
virtual Array shaped_text_get_objects(const RID &p_shaped) const override;
virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override;
+ virtual Vector2i shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const override;
+ virtual int64_t shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const override;
GDVIRTUAL1RC(Array, _shaped_text_get_objects, RID);
GDVIRTUAL2RC(Rect2, _shaped_text_get_object_rect, RID, const Variant &);
+ GDVIRTUAL2RC(Vector2i, _shaped_text_get_object_range, RID, const Variant &);
+ GDVIRTUAL2RC(int64_t, _shaped_text_get_object_glyph, RID, const Variant &);
virtual Size2 shaped_text_get_size(const RID &p_shaped) const override;
virtual double shaped_text_get_ascent(const RID &p_shaped) const override;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index d1dadbc8399..9cba9680262 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -443,6 +443,8 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shaped_text_get_objects", "shaped"), &TextServer::shaped_text_get_objects);
ClassDB::bind_method(D_METHOD("shaped_text_get_object_rect", "shaped", "key"), &TextServer::shaped_text_get_object_rect);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_object_range", "shaped", "key"), &TextServer::shaped_text_get_object_range);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_object_glyph", "shaped", "key"), &TextServer::shaped_text_get_object_glyph);
ClassDB::bind_method(D_METHOD("shaped_text_get_size", "shaped"), &TextServer::shaped_text_get_size);
ClassDB::bind_method(D_METHOD("shaped_text_get_ascent", "shaped"), &TextServer::shaped_text_get_ascent);
diff --git a/servers/text_server.h b/servers/text_server.h
index dfd6140fde1..55c7d8a88ea 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -490,6 +490,8 @@ public:
virtual Array shaped_text_get_objects(const RID &p_shaped) const = 0;
virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const = 0;
+ virtual Vector2i shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const = 0;
+ virtual int64_t shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const = 0;
virtual Size2 shaped_text_get_size(const RID &p_shaped) const = 0;
virtual double shaped_text_get_ascent(const RID &p_shaped) const = 0;