[Complex Text Layouts] Performance optimizations.
This commit is contained in:
parent
a41f1c67e5
commit
0ef483e9a9
7 changed files with 211 additions and 124 deletions
|
@ -56,11 +56,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
|
||||||
int paren_sp = -1;
|
int paren_sp = -1;
|
||||||
int start_sp = paren_sp;
|
int start_sp = paren_sp;
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
|
const char32_t *str = p_string.ptr();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
script_code = USCRIPT_COMMON;
|
script_code = USCRIPT_COMMON;
|
||||||
for (script_start = script_end; script_end < p_length; script_end++) {
|
for (script_start = script_end; script_end < p_length; script_end++) {
|
||||||
UChar32 ch = p_string[script_end];
|
UChar32 ch = str[script_end];
|
||||||
UScriptCode sc = uscript_getScript(ch, &err);
|
UScriptCode sc = uscript_getScript(ch, &err);
|
||||||
if (U_FAILURE(err)) {
|
if (U_FAILURE(err)) {
|
||||||
ERR_FAIL_MSG(u_errorName(err));
|
ERR_FAIL_MSG(u_errorName(err));
|
||||||
|
|
|
@ -1108,7 +1108,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
|
||||||
sd->width = 0;
|
sd->width = 0;
|
||||||
sd->upos = 0;
|
sd->upos = 0;
|
||||||
sd->uthk = 0;
|
sd->uthk = 0;
|
||||||
for (int i = 0; i < sd->glyphs.size(); i++) {
|
int sd_size = sd->glyphs.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < sd_size; i++) {
|
||||||
Glyph gl = sd->glyphs[i];
|
Glyph gl = sd->glyphs[i];
|
||||||
Variant key;
|
Variant key;
|
||||||
if (gl.count == 1) {
|
if (gl.count == 1) {
|
||||||
|
@ -1248,6 +1250,11 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
|
||||||
new_sd->utf16 = new_sd->text.utf16();
|
new_sd->utf16 = new_sd->text.utf16();
|
||||||
new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length()));
|
new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length()));
|
||||||
|
|
||||||
|
int sd_size = sd->glyphs.size();
|
||||||
|
const Glyph *sd_glyphs = sd->glyphs.ptr();
|
||||||
|
const FontDataAdvanced *fd = nullptr;
|
||||||
|
RID prev_rid = RID();
|
||||||
|
|
||||||
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
|
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
|
|
||||||
|
@ -1280,21 +1287,23 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
|
||||||
int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start);
|
int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start);
|
||||||
int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
|
int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
|
||||||
|
|
||||||
for (int j = 0; j < sd->glyphs.size(); j++) {
|
for (int j = 0; j < sd_size; j++) {
|
||||||
if ((sd->glyphs[j].start >= bidi_run_start) && (sd->glyphs[j].end <= bidi_run_end)) {
|
if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
|
||||||
// Copy glyphs.
|
// Copy glyphs.
|
||||||
Glyph gl = sd->glyphs[j];
|
Glyph gl = sd_glyphs[j];
|
||||||
Variant key;
|
Variant key;
|
||||||
|
bool find_embedded = false;
|
||||||
if (gl.count == 1) {
|
if (gl.count == 1) {
|
||||||
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
|
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
|
||||||
if (E->get().pos == gl.start) {
|
if (E->get().pos == gl.start) {
|
||||||
|
find_embedded = true;
|
||||||
key = E->key();
|
key = E->key();
|
||||||
new_sd->objects[key] = E->get();
|
new_sd->objects[key] = E->get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (key != Variant()) {
|
if (find_embedded) {
|
||||||
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||||
new_sd->objects[key].rect.position.x = new_sd->width;
|
new_sd->objects[key].rect.position.x = new_sd->width;
|
||||||
new_sd->width += new_sd->objects[key].rect.size.x;
|
new_sd->width += new_sd->objects[key].rect.size.x;
|
||||||
|
@ -1327,7 +1336,10 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const FontDataAdvanced *fd = font_owner.getornull(gl.font_rid);
|
if (prev_rid != gl.font_rid) {
|
||||||
|
fd = font_owner.getornull(gl.font_rid);
|
||||||
|
prev_rid = gl.font_rid;
|
||||||
|
}
|
||||||
if (fd != nullptr) {
|
if (fd != nullptr) {
|
||||||
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||||
new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
|
new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
|
||||||
|
@ -1529,8 +1541,10 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
|
||||||
delta = -1;
|
delta = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glyph *gl = sd->glyphs.ptrw();
|
||||||
|
|
||||||
for (int i = start; i != end; i += delta) {
|
for (int i = start; i != end; i += delta) {
|
||||||
if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
|
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
|
||||||
float tab_off = 0.f;
|
float tab_off = 0.f;
|
||||||
while (tab_off <= off) {
|
while (tab_off <= off) {
|
||||||
tab_off += p_tab_stops[tab_index];
|
tab_off += p_tab_stops[tab_index];
|
||||||
|
@ -1539,13 +1553,13 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
|
||||||
tab_index = 0;
|
tab_index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
float old_adv = sd->glyphs.write[i].advance;
|
float old_adv = gl[i].advance;
|
||||||
sd->glyphs.write[i].advance = tab_off - off;
|
gl[i].advance = tab_off - off;
|
||||||
sd->width += sd->glyphs.write[i].advance - old_adv;
|
sd->width += gl[i].advance - old_adv;
|
||||||
off = 0;
|
off = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
off += sd->glyphs[i].advance * sd->glyphs[i].repeat;
|
off += gl[i].advance * gl[i].repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
@ -1565,8 +1579,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
|
||||||
|
|
||||||
const UChar *data = sd->utf16.ptr();
|
const UChar *data = sd->utf16.ptr();
|
||||||
|
|
||||||
Map<int, bool> breaks;
|
HashMap<int, bool> breaks;
|
||||||
|
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
for (int i = 0; i < sd->spans.size(); i++) {
|
for (int i = 0; i < sd->spans.size(); i++) {
|
||||||
UBreakIterator *bi = ubrk_open(UBRK_LINE, sd->spans[i].language.ascii().get_data(), data + _convert_pos_inv(sd, sd->spans[i].start), _convert_pos_inv(sd, sd->spans[i].end - sd->spans[i].start), &err);
|
UBreakIterator *bi = ubrk_open(UBRK_LINE, sd->spans[i].language.ascii().get_data(), data + _convert_pos_inv(sd, sd->spans[i].start), _convert_pos_inv(sd, sd->spans[i].end - sd->spans[i].start), &err);
|
||||||
|
@ -1598,40 +1611,48 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
|
||||||
|
|
||||||
sd->sort_valid = false;
|
sd->sort_valid = false;
|
||||||
sd->glyphs_logical.clear();
|
sd->glyphs_logical.clear();
|
||||||
|
int sd_size = sd->glyphs.size();
|
||||||
|
const char32_t *ch = sd->text.ptr();
|
||||||
|
Glyph *sd_glyphs = sd->glyphs.ptrw();
|
||||||
|
|
||||||
for (int i = 0; i < sd->glyphs.size(); i++) {
|
for (int i = 0; i < sd_size; i++) {
|
||||||
if (sd->glyphs[i].count > 0) {
|
if (sd_glyphs[i].count > 0) {
|
||||||
char32_t c = sd->text[sd->glyphs[i].start - sd->start];
|
char32_t c = ch[sd_glyphs[i].start - sd->start];
|
||||||
if (c == 0xfffc) {
|
if (c == 0xfffc) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == 0x0009 || c == 0x000b) {
|
if (c == 0x0009 || c == 0x000b) {
|
||||||
sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB;
|
sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
|
||||||
}
|
}
|
||||||
if (breaks.has(sd->glyphs[i].start)) {
|
if (breaks.has(sd->glyphs[i].start)) {
|
||||||
if (breaks[sd->glyphs[i].start]) {
|
if (breaks[sd->glyphs[i].start]) {
|
||||||
sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD;
|
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
|
||||||
} else {
|
} else {
|
||||||
if (is_whitespace(c)) {
|
if (is_whitespace(c)) {
|
||||||
sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT;
|
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
|
||||||
sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE;
|
sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
|
||||||
} else {
|
} else {
|
||||||
TextServer::Glyph gl;
|
TextServer::Glyph gl;
|
||||||
gl.start = sd->glyphs[i].start;
|
gl.start = sd_glyphs[i].start;
|
||||||
gl.end = sd->glyphs[i].end;
|
gl.end = sd_glyphs[i].end;
|
||||||
gl.count = 1;
|
gl.count = 1;
|
||||||
gl.repeat = 1;
|
gl.repeat = 1;
|
||||||
gl.font_rid = sd->glyphs[i].font_rid;
|
gl.font_rid = sd_glyphs[i].font_rid;
|
||||||
gl.font_size = sd->glyphs[i].font_size;
|
gl.font_size = sd_glyphs[i].font_size;
|
||||||
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
|
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
|
||||||
sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after
|
sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after
|
||||||
i += sd->glyphs[i].count;
|
|
||||||
|
// Update write pointer and size.
|
||||||
|
sd_size = sd->glyphs.size();
|
||||||
|
sd_glyphs = sd->glyphs.ptrw();
|
||||||
|
|
||||||
|
i += sd_glyphs[i].count;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i += (sd->glyphs[i].count - 1);
|
i += (sd_glyphs[i].count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1767,9 +1788,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
|
||||||
|
|
||||||
sd->sort_valid = false;
|
sd->sort_valid = false;
|
||||||
sd->glyphs_logical.clear();
|
sd->glyphs_logical.clear();
|
||||||
|
int sd_size = sd->glyphs.size();
|
||||||
|
|
||||||
if (jstops.size() > 0) {
|
if (jstops.size() > 0) {
|
||||||
for (int i = 0; i < sd->glyphs.size(); i++) {
|
for (int i = 0; i < sd_size; i++) {
|
||||||
if (sd->glyphs[i].count > 0) {
|
if (sd->glyphs[i].count > 0) {
|
||||||
if (jstops.has(sd->glyphs[i].start)) {
|
if (jstops.has(sd->glyphs[i].start)) {
|
||||||
char32_t c = sd->text[sd->glyphs[i].start - sd->start];
|
char32_t c = sd->text[sd->glyphs[i].start - sd->start];
|
||||||
|
@ -1873,6 +1895,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
||||||
fd = font_owner.getornull(p_fonts[p_fb_index]);
|
fd = font_owner.getornull(p_fonts[p_fb_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fs = p_sd->spans[p_span].font_size;
|
||||||
if (fd == nullptr) {
|
if (fd == nullptr) {
|
||||||
// Add fallback glyphs
|
// Add fallback glyphs
|
||||||
for (int i = p_start; i < p_end; i++) {
|
for (int i = p_start; i < p_end; i++) {
|
||||||
|
@ -1882,20 +1905,20 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
||||||
gl.end = i + 1;
|
gl.end = i + 1;
|
||||||
gl.count = 1;
|
gl.count = 1;
|
||||||
gl.index = p_sd->text[i];
|
gl.index = p_sd->text[i];
|
||||||
gl.font_size = p_sd->spans[p_span].font_size;
|
gl.font_size = fs;
|
||||||
gl.font_rid = RID();
|
gl.font_rid = RID();
|
||||||
gl.flags = 0;
|
gl.flags = 0;
|
||||||
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
|
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
|
||||||
gl.flags |= TextServer::GRAPHEME_IS_RTL;
|
gl.flags |= TextServer::GRAPHEME_IS_RTL;
|
||||||
}
|
}
|
||||||
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
|
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||||
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
|
gl.advance = get_hex_code_box_size(fs, gl.index).x;
|
||||||
p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
|
p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f));
|
||||||
p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
|
p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f));
|
||||||
} else {
|
} else {
|
||||||
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
|
gl.advance = get_hex_code_box_size(fs, gl.index).y;
|
||||||
p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
|
p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
|
||||||
p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
|
p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
|
||||||
}
|
}
|
||||||
p_sd->width += gl.advance;
|
p_sd->width += gl.advance;
|
||||||
|
|
||||||
|
@ -1905,7 +1928,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_font_t *hb_font = fd->get_hb_handle(p_sd->spans[p_span].font_size);
|
hb_font_t *hb_font = fd->get_hb_handle(fs);
|
||||||
ERR_FAIL_COND(hb_font == nullptr);
|
ERR_FAIL_COND(hb_font == nullptr);
|
||||||
|
|
||||||
hb_buffer_clear_contents(p_sd->hb_buffer);
|
hb_buffer_clear_contents(p_sd->hb_buffer);
|
||||||
|
@ -1981,17 +2004,17 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
||||||
gl.count = 0;
|
gl.count = 0;
|
||||||
|
|
||||||
gl.font_rid = p_fonts[p_fb_index];
|
gl.font_rid = p_fonts[p_fb_index];
|
||||||
gl.font_size = p_sd->spans[p_span].font_size;
|
gl.font_size = fs;
|
||||||
|
|
||||||
gl.index = glyph_info[i].codepoint;
|
gl.index = glyph_info[i].codepoint;
|
||||||
if (gl.index != 0) {
|
if (gl.index != 0) {
|
||||||
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
|
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||||
gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(gl.font_size)));
|
gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(fs)));
|
||||||
} else {
|
} else {
|
||||||
gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(gl.font_size)));
|
gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(fs)));
|
||||||
}
|
}
|
||||||
gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(gl.font_size)));
|
gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs)));
|
||||||
gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(gl.font_size)));
|
gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_sd->preserve_control) {
|
if (p_sd->preserve_control) {
|
||||||
|
@ -2026,14 +2049,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
||||||
}
|
}
|
||||||
for (int j = 0; j < w[i].count; j++) {
|
for (int j = 0; j < w[i].count; j++) {
|
||||||
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
|
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||||
p_sd->ascent = MAX(p_sd->ascent, MAX(fd->get_ascent(w[i + j].font_size), -w[i + j].y_off));
|
p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);
|
||||||
p_sd->descent = MAX(p_sd->descent, MAX(fd->get_descent(w[i + j].font_size), w[i + j].y_off));
|
p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);
|
||||||
} else {
|
} else {
|
||||||
p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5));
|
p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
|
||||||
p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5));
|
p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
|
||||||
}
|
}
|
||||||
p_sd->upos = MAX(p_sd->upos, font_get_underline_position(w[i + j].font_rid, w[i + j].font_size));
|
|
||||||
p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(w[i + j].font_rid, w[i + j].font_size));
|
|
||||||
p_sd->width += w[i + j].advance;
|
p_sd->width += w[i + j].advance;
|
||||||
p_sd->glyphs.push_back(w[i + j]);
|
p_sd->glyphs.push_back(w[i + j]);
|
||||||
}
|
}
|
||||||
|
@ -2051,6 +2072,10 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
||||||
if (failed_subrun_start != p_end + 1) {
|
if (failed_subrun_start != p_end + 1) {
|
||||||
_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1);
|
_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1);
|
||||||
}
|
}
|
||||||
|
p_sd->ascent = MAX(p_sd->ascent, fd->get_ascent(fs));
|
||||||
|
p_sd->descent = MAX(p_sd->descent, fd->get_descent(fs));
|
||||||
|
p_sd->upos = MAX(p_sd->upos, fd->get_underline_position(fs));
|
||||||
|
p_sd->uthk = MAX(p_sd->uthk, fd->get_underline_thickness(fs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -625,7 +625,11 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
|
||||||
sd->width = 0;
|
sd->width = 0;
|
||||||
sd->upos = 0;
|
sd->upos = 0;
|
||||||
sd->uthk = 0;
|
sd->uthk = 0;
|
||||||
for (int i = 0; i < sd->glyphs.size(); i++) {
|
int sd_size = sd->glyphs.size();
|
||||||
|
const FontDataFallback *fd = nullptr;
|
||||||
|
RID prev_rid = RID();
|
||||||
|
|
||||||
|
for (int i = 0; i < sd_size; i++) {
|
||||||
Glyph gl = sd->glyphs[i];
|
Glyph gl = sd->glyphs[i];
|
||||||
Variant key;
|
Variant key;
|
||||||
if (gl.count == 1) {
|
if (gl.count == 1) {
|
||||||
|
@ -671,7 +675,10 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
|
||||||
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
|
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const FontDataFallback *fd = font_owner.getornull(gl.font_rid);
|
if (prev_rid != gl.font_rid) {
|
||||||
|
fd = font_owner.getornull(gl.font_rid);
|
||||||
|
prev_rid = gl.font_rid;
|
||||||
|
}
|
||||||
if (fd != nullptr) {
|
if (fd != nullptr) {
|
||||||
if (sd->orientation == ORIENTATION_HORIZONTAL) {
|
if (sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||||
sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size));
|
sd->ascent = MAX(sd->ascent, fd->get_ascent(gl.font_size));
|
||||||
|
@ -760,21 +767,25 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
|
||||||
|
|
||||||
if (p_length > 0) {
|
if (p_length > 0) {
|
||||||
new_sd->text = sd->text.substr(p_start, p_length);
|
new_sd->text = sd->text.substr(p_start, p_length);
|
||||||
|
int sd_size = sd->glyphs.size();
|
||||||
|
const Glyph *sd_glyphs = sd->glyphs.ptr();
|
||||||
|
|
||||||
for (int i = 0; i < sd->glyphs.size(); i++) {
|
for (int i = 0; i < sd_size; i++) {
|
||||||
if ((sd->glyphs[i].start >= new_sd->start) && (sd->glyphs[i].end <= new_sd->end)) {
|
if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {
|
||||||
Glyph gl = sd->glyphs[i];
|
Glyph gl = sd_glyphs[i];
|
||||||
Variant key;
|
Variant key;
|
||||||
|
bool find_embedded = false;
|
||||||
if (gl.count == 1) {
|
if (gl.count == 1) {
|
||||||
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
|
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
|
||||||
if (E->get().pos == gl.start) {
|
if (E->get().pos == gl.start) {
|
||||||
|
find_embedded = true;
|
||||||
key = E->key();
|
key = E->key();
|
||||||
new_sd->objects[key] = E->get();
|
new_sd->objects[key] = E->get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (key != Variant()) {
|
if (find_embedded) {
|
||||||
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
|
||||||
new_sd->objects[key].rect.position.x = new_sd->width;
|
new_sd->objects[key].rect.position.x = new_sd->width;
|
||||||
new_sd->width += new_sd->objects[key].rect.size.x;
|
new_sd->width += new_sd->objects[key].rect.size.x;
|
||||||
|
@ -978,8 +989,10 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float
|
||||||
delta = -1;
|
delta = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glyph *gl = sd->glyphs.ptrw();
|
||||||
|
|
||||||
for (int i = start; i != end; i += delta) {
|
for (int i = start; i != end; i += delta) {
|
||||||
if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
|
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
|
||||||
float tab_off = 0.f;
|
float tab_off = 0.f;
|
||||||
while (tab_off <= off) {
|
while (tab_off <= off) {
|
||||||
tab_off += p_tab_stops[tab_index];
|
tab_off += p_tab_stops[tab_index];
|
||||||
|
@ -988,13 +1001,13 @@ float TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<float
|
||||||
tab_index = 0;
|
tab_index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
float old_adv = sd->glyphs.write[i].advance;
|
float old_adv = gl[i].advance;
|
||||||
sd->glyphs.write[i].advance = tab_off - off;
|
gl[i].advance = tab_off - off;
|
||||||
sd->width += sd->glyphs.write[i].advance - old_adv;
|
sd->width += gl[i].advance - old_adv;
|
||||||
off = 0;
|
off = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
off += sd->glyphs[i].advance * sd->glyphs[i].repeat;
|
off += gl[i].advance * gl[i].repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
@ -1012,7 +1025,8 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
|
||||||
return true; // Noting to do.
|
return true; // Noting to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < sd->glyphs.size(); i++) {
|
int sd_size = sd->glyphs.size();
|
||||||
|
for (int i = 0; i < sd_size; i++) {
|
||||||
if (sd->glyphs[i].count > 0) {
|
if (sd->glyphs[i].count > 0) {
|
||||||
char32_t c = sd->text[sd->glyphs[i].start];
|
char32_t c = sd->text[sd->glyphs[i].start];
|
||||||
if (is_whitespace(c) && !is_linebreak(c)) {
|
if (is_whitespace(c) && !is_linebreak(c)) {
|
||||||
|
@ -1163,8 +1177,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
|
||||||
sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
|
sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size));
|
sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size));
|
||||||
sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size));
|
sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size));
|
||||||
|
|
||||||
// Add kerning to previous glyph.
|
// Add kerning to previous glyph.
|
||||||
if (sd->glyphs.size() > 0) {
|
if (sd->glyphs.size() > 0) {
|
||||||
|
|
|
@ -251,8 +251,10 @@ void Label::_notification(int p_what) {
|
||||||
if (percent_visible < 1) {
|
if (percent_visible < 1) {
|
||||||
int total_glyphs = 0;
|
int total_glyphs = 0;
|
||||||
for (int i = lines_skipped; i < last_line; i++) {
|
for (int i = lines_skipped; i < last_line; i++) {
|
||||||
const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
|
const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
|
||||||
for (int j = 0; j < glyphs.size(); j++) {
|
const TextServer::Glyph *glyphs = visual.ptr();
|
||||||
|
int gl_size = visual.size();
|
||||||
|
for (int j = 0; j < gl_size; j++) {
|
||||||
if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
|
if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
|
||||||
total_glyphs++;
|
total_glyphs++;
|
||||||
}
|
}
|
||||||
|
@ -287,11 +289,13 @@ void Label::_notification(int p_what) {
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
|
const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
|
||||||
|
const TextServer::Glyph *glyphs = visual.ptr();
|
||||||
|
int gl_size = visual.size();
|
||||||
|
|
||||||
float x = ofs.x;
|
float x = ofs.x;
|
||||||
int outlines_drawn = glyhps_drawn;
|
int outlines_drawn = glyhps_drawn;
|
||||||
for (int j = 0; j < glyphs.size(); j++) {
|
for (int j = 0; j < gl_size; j++) {
|
||||||
for (int k = 0; k < glyphs[j].repeat; k++) {
|
for (int k = 0; k < glyphs[j].repeat; k++) {
|
||||||
if (glyphs[j].font_rid != RID()) {
|
if (glyphs[j].font_rid != RID()) {
|
||||||
if (font_color_shadow.a > 0) {
|
if (font_color_shadow.a > 0) {
|
||||||
|
@ -320,7 +324,7 @@ void Label::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
ofs.x = x;
|
ofs.x = x;
|
||||||
|
|
||||||
for (int j = 0; j < glyphs.size(); j++) {
|
for (int j = 0; j < gl_size; j++) {
|
||||||
for (int k = 0; k < glyphs[j].repeat; k++) {
|
for (int k = 0; k < glyphs[j].repeat; k++) {
|
||||||
if (glyphs[j].font_rid != RID()) {
|
if (glyphs[j].font_rid != RID()) {
|
||||||
TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_color);
|
TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_color);
|
||||||
|
|
|
@ -834,11 +834,13 @@ void LineEdit::_notification(int p_what) {
|
||||||
RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color);
|
RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(text_rid);
|
const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(text_rid);
|
||||||
|
const TextServer::Glyph *glyphs = visual.ptr();
|
||||||
|
int gl_size = visual.size();
|
||||||
|
|
||||||
// Draw text.
|
// Draw text.
|
||||||
ofs.y += TS->shaped_text_get_ascent(text_rid);
|
ofs.y += TS->shaped_text_get_ascent(text_rid);
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
for (int i = 0; i < gl_size; i++) {
|
||||||
bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end;
|
bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end;
|
||||||
for (int j = 0; j < glyphs[i].repeat; j++) {
|
for (int j = 0; j < glyphs[i].repeat; j++) {
|
||||||
if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) {
|
if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) {
|
||||||
|
|
|
@ -1240,10 +1240,13 @@ void TextEdit::_notification(int p_what) {
|
||||||
|
|
||||||
ofs_y += (row_height - text_height) / 2;
|
ofs_y += (row_height - text_height) / 2;
|
||||||
|
|
||||||
const Vector<TextServer::Glyph> glyphs = TS->shaped_text_get_glyphs(rid);
|
const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid);
|
||||||
|
const TextServer::Glyph *glyphs = visual.ptr();
|
||||||
|
int gl_size = visual.size();
|
||||||
|
|
||||||
ofs_y += ldata->get_line_ascent(line_wrap_index);
|
ofs_y += ldata->get_line_ascent(line_wrap_index);
|
||||||
float char_ofs = 0.f;
|
float char_ofs = 0.f;
|
||||||
for (int j = 0; j < glyphs.size(); j++) {
|
for (int j = 0; j < gl_size; j++) {
|
||||||
if (color_map.has(glyphs[j].start)) {
|
if (color_map.has(glyphs[j].start)) {
|
||||||
current_color = color_map[glyphs[j].start].get("color");
|
current_color = color_map[glyphs[j].start].get("color");
|
||||||
if (readonly && current_color.a > cache.font_color_readonly.a) {
|
if (readonly && current_color.a > cache.font_color_readonly.a) {
|
||||||
|
|
|
@ -554,14 +554,18 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
|
||||||
int line_start = MAX(p_start, range.x);
|
int line_start = MAX(p_start, range.x);
|
||||||
int last_safe_break = -1;
|
int last_safe_break = -1;
|
||||||
int chunk = 0;
|
int chunk = 0;
|
||||||
for (int i = 0; i < logical.size(); i++) {
|
|
||||||
if (logical[i].start < p_start) {
|
int l_size = logical.size();
|
||||||
|
const Glyph *l_gl = logical.ptr();
|
||||||
|
|
||||||
|
for (int i = 0; i < l_size; i++) {
|
||||||
|
if (l_gl[i].start < p_start) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (logical[i].count > 0) {
|
if (l_gl[i].count > 0) {
|
||||||
if ((p_width[chunk] > 0) && (width + logical[i].advance > p_width[chunk]) && (last_safe_break >= 0)) {
|
if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) {
|
||||||
lines.push_back(Vector2i(line_start, logical[last_safe_break].end));
|
lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end));
|
||||||
line_start = logical[last_safe_break].end;
|
line_start = l_gl[last_safe_break].end;
|
||||||
i = last_safe_break;
|
i = last_safe_break;
|
||||||
last_safe_break = -1;
|
last_safe_break = -1;
|
||||||
width = 0;
|
width = 0;
|
||||||
|
@ -575,9 +579,9 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
|
if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
|
||||||
if ((logical[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
|
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
|
||||||
lines.push_back(Vector2i(line_start, logical[i].end));
|
lines.push_back(Vector2i(line_start, l_gl[i].end));
|
||||||
line_start = logical[i].end;
|
line_start = l_gl[i].end;
|
||||||
last_safe_break = -1;
|
last_safe_break = -1;
|
||||||
width = 0;
|
width = 0;
|
||||||
chunk = 0;
|
chunk = 0;
|
||||||
|
@ -588,7 +592,7 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) {
|
if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) {
|
||||||
if ((logical[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
|
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
|
||||||
last_safe_break = i;
|
last_safe_break = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -596,10 +600,10 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
|
||||||
last_safe_break = i;
|
last_safe_break = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width += logical[i].advance;
|
width += l_gl[i].advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logical.size() > 0) {
|
if (l_size > 0) {
|
||||||
lines.push_back(Vector2i(line_start, range.y));
|
lines.push_back(Vector2i(line_start, range.y));
|
||||||
} else {
|
} else {
|
||||||
lines.push_back(Vector2i(0, 0));
|
lines.push_back(Vector2i(0, 0));
|
||||||
|
@ -618,30 +622,34 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
|
||||||
float width = 0.f;
|
float width = 0.f;
|
||||||
int line_start = MAX(p_start, range.x);
|
int line_start = MAX(p_start, range.x);
|
||||||
int last_safe_break = -1;
|
int last_safe_break = -1;
|
||||||
for (int i = 0; i < logical.size(); i++) {
|
|
||||||
if (logical[i].start < p_start) {
|
int l_size = logical.size();
|
||||||
|
const Glyph *l_gl = logical.ptr();
|
||||||
|
|
||||||
|
for (int i = 0; i < l_size; i++) {
|
||||||
|
if (l_gl[i].start < p_start) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (logical[i].count > 0) {
|
if (l_gl[i].count > 0) {
|
||||||
if ((p_width > 0) && (width + logical[i].advance > p_width) && (last_safe_break >= 0)) {
|
if ((p_width > 0) && (width + l_gl[i].advance > p_width) && (last_safe_break >= 0)) {
|
||||||
lines.push_back(Vector2i(line_start, logical[last_safe_break].end));
|
lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end));
|
||||||
line_start = logical[last_safe_break].end;
|
line_start = l_gl[last_safe_break].end;
|
||||||
i = last_safe_break;
|
i = last_safe_break;
|
||||||
last_safe_break = -1;
|
last_safe_break = -1;
|
||||||
width = 0;
|
width = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
|
if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
|
||||||
if ((logical[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
|
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
|
||||||
lines.push_back(Vector2i(line_start, logical[i].end));
|
lines.push_back(Vector2i(line_start, l_gl[i].end));
|
||||||
line_start = logical[i].end;
|
line_start = l_gl[i].end;
|
||||||
last_safe_break = -1;
|
last_safe_break = -1;
|
||||||
width = 0;
|
width = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) {
|
if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) {
|
||||||
if ((logical[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
|
if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
|
||||||
last_safe_break = i;
|
last_safe_break = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,10 +657,10 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_w
|
||||||
last_safe_break = i;
|
last_safe_break = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width += logical[i].advance;
|
width += l_gl[i].advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logical.size() > 0) {
|
if (l_size > 0) {
|
||||||
if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) {
|
if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) {
|
||||||
lines.push_back(Vector2i(line_start, range.y));
|
lines.push_back(Vector2i(line_start, range.y));
|
||||||
}
|
}
|
||||||
|
@ -671,15 +679,19 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
|
||||||
const Vector2i &range = shaped_text_get_range(p_shaped);
|
const Vector2i &range = shaped_text_get_range(p_shaped);
|
||||||
|
|
||||||
int word_start = range.x;
|
int word_start = range.x;
|
||||||
for (int i = 0; i < logical.size(); i++) {
|
|
||||||
if (logical[i].count > 0) {
|
int l_size = logical.size();
|
||||||
if ((logical[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
|
const Glyph *l_gl = logical.ptr();
|
||||||
words.push_back(Vector2i(word_start, logical[i].end - 1));
|
|
||||||
word_start = logical[i].end;
|
for (int i = 0; i < l_size; i++) {
|
||||||
|
if (l_gl[i].count > 0) {
|
||||||
|
if ((l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
|
||||||
|
words.push_back(Vector2i(word_start, l_gl[i].end - 1));
|
||||||
|
word_start = l_gl[i].end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (logical.size() > 0) {
|
if (l_size > 0) {
|
||||||
words.push_back(Vector2i(word_start, range.y));
|
words.push_back(Vector2i(word_start, range.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +700,7 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const {
|
||||||
|
|
||||||
void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const {
|
void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const {
|
||||||
Vector<Rect2> carets;
|
Vector<Rect2> carets;
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
|
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
|
||||||
const Vector2 &range = shaped_text_get_range(p_shaped);
|
const Vector2 &range = shaped_text_get_range(p_shaped);
|
||||||
float ascent = shaped_text_get_ascent(p_shaped);
|
float ascent = shaped_text_get_ascent(p_shaped);
|
||||||
|
@ -698,7 +710,11 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
|
||||||
float off = 0.0f;
|
float off = 0.0f;
|
||||||
p_leading_dir = DIRECTION_AUTO;
|
p_leading_dir = DIRECTION_AUTO;
|
||||||
p_trailing_dir = DIRECTION_AUTO;
|
p_trailing_dir = DIRECTION_AUTO;
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
|
||||||
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
|
||||||
|
for (int i = 0; i < v_size; i++) {
|
||||||
if (glyphs[i].count > 0) {
|
if (glyphs[i].count > 0) {
|
||||||
// Caret before grapheme (top / left).
|
// Caret before grapheme (top / left).
|
||||||
if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
|
if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
|
||||||
|
@ -831,7 +847,7 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
|
||||||
}
|
}
|
||||||
|
|
||||||
TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const {
|
TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const {
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
|
|
||||||
if (p_start == p_end) {
|
if (p_start == p_end) {
|
||||||
return DIRECTION_AUTO;
|
return DIRECTION_AUTO;
|
||||||
|
@ -843,7 +859,10 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI
|
||||||
int rtl = 0;
|
int rtl = 0;
|
||||||
int ltr = 0;
|
int ltr = 0;
|
||||||
|
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
|
||||||
|
for (int i = 0; i < v_size; i++) {
|
||||||
if ((glyphs[i].end > start) && (glyphs[i].start < end)) {
|
if ((glyphs[i].end > start) && (glyphs[i].start < end)) {
|
||||||
if (glyphs[i].count > 0) {
|
if (glyphs[i].count > 0) {
|
||||||
if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
|
if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
|
||||||
|
@ -865,7 +884,7 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI
|
||||||
|
|
||||||
Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
|
Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
|
||||||
Vector<Vector2> ranges;
|
Vector<Vector2> ranges;
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
|
|
||||||
if (p_start == p_end) {
|
if (p_start == p_end) {
|
||||||
return ranges;
|
return ranges;
|
||||||
|
@ -874,8 +893,11 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
|
||||||
int start = MIN(p_start, p_end);
|
int start = MIN(p_start, p_end);
|
||||||
int end = MAX(p_start, p_end);
|
int end = MAX(p_start, p_end);
|
||||||
|
|
||||||
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
|
||||||
float off = 0.0f;
|
float off = 0.0f;
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
for (int i = 0; i < v_size; i++) {
|
||||||
for (int k = 0; k < glyphs[i].repeat; k++) {
|
for (int k = 0; k < glyphs[i].repeat; k++) {
|
||||||
if (glyphs[i].count > 0 && glyphs[i].index != 0) {
|
if (glyphs[i].count > 0 && glyphs[i].index != 0) {
|
||||||
if (glyphs[i].start < end && glyphs[i].end > start) {
|
if (glyphs[i].start < end && glyphs[i].end > start) {
|
||||||
|
@ -951,11 +973,15 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const {
|
int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const {
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
|
|
||||||
// Exact grapheme hit test, return -1 if missed.
|
// Exact grapheme hit test, return -1 if missed.
|
||||||
float off = 0.0f;
|
float off = 0.0f;
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
|
||||||
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
|
||||||
|
for (int i = 0; i < v_size; i++) {
|
||||||
for (int j = 0; j < glyphs[i].repeat; j++) {
|
for (int j = 0; j < glyphs[i].repeat; j++) {
|
||||||
if (p_coords >= off && p_coords < off + glyphs[i].advance) {
|
if (p_coords >= off && p_coords < off + glyphs[i].advance) {
|
||||||
return i;
|
return i;
|
||||||
|
@ -967,13 +993,16 @@ int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) cons
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) const {
|
int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) const {
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
|
|
||||||
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
|
||||||
// Cursor placement hit test.
|
// Cursor placement hit test.
|
||||||
|
|
||||||
// Place caret to the left of the leftmost grapheme, or to position 0 if string is empty.
|
// Place caret to the left of the leftmost grapheme, or to position 0 if string is empty.
|
||||||
if (p_coords <= 0) {
|
if (p_coords <= 0) {
|
||||||
if (glyphs.size() > 0) {
|
if (v_size > 0) {
|
||||||
if ((glyphs[0].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
|
if ((glyphs[0].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
|
||||||
return glyphs[0].end;
|
return glyphs[0].end;
|
||||||
} else {
|
} else {
|
||||||
|
@ -986,11 +1015,11 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) cons
|
||||||
|
|
||||||
// Place caret to the right of the rightmost grapheme, or to position 0 if string is empty.
|
// Place caret to the right of the rightmost grapheme, or to position 0 if string is empty.
|
||||||
if (p_coords >= shaped_text_get_width(p_shaped)) {
|
if (p_coords >= shaped_text_get_width(p_shaped)) {
|
||||||
if (glyphs.size() > 0) {
|
if (v_size > 0) {
|
||||||
if ((glyphs[glyphs.size() - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
|
if ((glyphs[v_size - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
|
||||||
return glyphs[glyphs.size() - 1].start;
|
return glyphs[v_size - 1].start;
|
||||||
} else {
|
} else {
|
||||||
return glyphs[glyphs.size() - 1].end;
|
return glyphs[v_size - 1].end;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -998,7 +1027,7 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) cons
|
||||||
}
|
}
|
||||||
|
|
||||||
float off = 0.0f;
|
float off = 0.0f;
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
for (int i = 0; i < v_size; i++) {
|
||||||
for (int k = 0; k < glyphs[i].repeat; k++) {
|
for (int k = 0; k < glyphs[i].repeat; k++) {
|
||||||
if (glyphs[i].count > 0) {
|
if (glyphs[i].count > 0) {
|
||||||
float advance = 0.f;
|
float advance = 0.f;
|
||||||
|
@ -1029,8 +1058,10 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) cons
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) {
|
int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) {
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
for (int i = 0; i < v_size; i++) {
|
||||||
if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) {
|
if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) {
|
||||||
return glyphs[i].end;
|
return glyphs[i].end;
|
||||||
}
|
}
|
||||||
|
@ -1039,8 +1070,10 @@ int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) {
|
int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) {
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
for (int i = 0; i < v_size; i++) {
|
||||||
if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) {
|
if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) {
|
||||||
return glyphs[i].start;
|
return glyphs[i].start;
|
||||||
}
|
}
|
||||||
|
@ -1050,13 +1083,16 @@ int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const {
|
void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const {
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
|
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
|
||||||
bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped);
|
bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped);
|
||||||
|
|
||||||
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
|
|
||||||
Vector2 ofs = p_pos;
|
Vector2 ofs = p_pos;
|
||||||
// Draw at the baseline.
|
// Draw at the baseline.
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
for (int i = 0; i < v_size; i++) {
|
||||||
for (int j = 0; j < glyphs[i].repeat; j++) {
|
for (int j = 0; j < glyphs[i].repeat; j++) {
|
||||||
if (p_clip_r > 0) {
|
if (p_clip_r > 0) {
|
||||||
// Clip right / bottom.
|
// Clip right / bottom.
|
||||||
|
@ -1099,12 +1135,14 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const {
|
void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const {
|
||||||
const Vector<TextServer::Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
|
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
|
||||||
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
|
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
|
||||||
|
|
||||||
|
int v_size = visual.size();
|
||||||
|
const Glyph *glyphs = visual.ptr();
|
||||||
Vector2 ofs = p_pos;
|
Vector2 ofs = p_pos;
|
||||||
// Draw at the baseline.
|
// Draw at the baseline.
|
||||||
for (int i = 0; i < glyphs.size(); i++) {
|
for (int i = 0; i < v_size; i++) {
|
||||||
for (int j = 0; j < glyphs[i].repeat; j++) {
|
for (int j = 0; j < glyphs[i].repeat; j++) {
|
||||||
if (p_clip_r > 0) {
|
if (p_clip_r > 0) {
|
||||||
// Clip right / bottom.
|
// Clip right / bottom.
|
||||||
|
|
Loading…
Reference in a new issue